diff --git a/docs/installationguide/debian.rst b/docs/installationguide/debian.rst index ea5fbeda1..8346abe00 100644 --- a/docs/installationguide/debian.rst +++ b/docs/installationguide/debian.rst @@ -4,7 +4,7 @@ Debian .. contents:: Easy Way: Debian 11 (Bullseye) ------------------------- +------------------------------ This procedure will guide you through the installation of ZoneMinder on Debian 11 (Bullseye). @@ -104,7 +104,7 @@ Add the following to the /etc/apt/sources.list.d/zoneminder.list file You can do this using: -.. code-block:: +:: echo "deb https://zmrepo.zoneminder.com/debian/release-1.36 buster/" | sudo tee /etc/apt/sources.list.d/zoneminder.list diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 3a3308938..0db46ff0d 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -230,8 +230,8 @@ sub Sql { # PostCondition, so no further SQL } else { ( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/; - foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) { - + # Empty value will result in () from split + foreach my $temp_value ( $stripped_value ? split( /["'\s]*?,["'\s]*?/, $stripped_value ) : $stripped_value ) { if ( $term->{attr} eq 'AlarmedZoneId' ) { $value = '(SELECT * FROM Stats WHERE EventId=E.Id AND Score > 0 AND ZoneId='.$value.')'; } elsif ( $term->{attr} =~ /^MonitorName/ ) { @@ -250,7 +250,8 @@ sub Sql { $$self{Server} = new ZoneMinder::Server($temp_value); } } elsif ( $term->{attr} eq 'StorageId' ) { - $value = "'$temp_value'"; + # Empty means NULL, otherwise must be an integer + $value = $temp_value ne '' ? int($temp_value) : 'NULL'; $$self{Storage} = new ZoneMinder::Storage($temp_value); } elsif ( $term->{attr} eq 'Name' || $term->{attr} eq 'Cause' 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'"); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 545d173d5..5d1cd1792 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1904,7 +1904,7 @@ bool Monitor::Analyse() { if (snap->image) { // decoder may not have been able to provide an image if (!ref_image.Buffer()) { - Debug(1, "Assigning instead of Dectecting"); + Debug(1, "Assigning instead of Detecting"); ref_image.Assign(*(snap->image)); } else { Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image); diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 126ed708e..5d7309435 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -377,9 +377,10 @@ bool MonitorStream::sendFrame(const char *filepath, const timeval ×tamp) { return false; } // end bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) -bool MonitorStream::sendFrame(Image *image, const timeval ×tamp) { - if (!config.timestamp_on_capture) +bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) { + if (!config.timestamp_on_capture) { monitor->TimestampImage(image, timestamp); + } Image *send_image = prepareImage(image); fputs("--" BOUNDARY "\r\n", stdout); @@ -863,6 +864,10 @@ 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 (!config.timestamp_on_capture) { monitor->TimestampImage(snap_image, monitor->shared_timestamps[index]); diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index ceef421db..8c088c1db 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 diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 41174857f..1aacacac7 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -874,16 +874,23 @@ std::vector Zone::Load(Monitor *monitor) { continue; } - if (polygon.Extent().Lo().x_ < 0 || polygon.Extent().Hi().x_ > static_cast(monitor->Width()) - || polygon.Extent().Lo().y_ < 0 || polygon.Extent().Hi().y_ > static_cast(monitor->Height())) { - Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), fixing", + if (polygon.Extent().Lo().x_ < 0 + || + polygon.Extent().Hi().x_ > static_cast(monitor->Width()) + || + polygon.Extent().Lo().y_ < 0 + || + polygon.Extent().Hi().y_ > static_cast(monitor->Height())) { + Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d) != (%d,%d), fixing", Id, Name, monitor->Name(), polygon.Extent().Lo().x_, polygon.Extent().Lo().y_, polygon.Extent().Hi().x_, - polygon.Extent().Hi().y_); + polygon.Extent().Hi().y_, + monitor->Width(), + monitor->Height()); polygon.Clip(Box( {0, 0}, diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index b425f7896..b441db349 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -152,7 +152,7 @@ $booleanValues = array( $focusWindow = true; -$storageareas = array('' => 'All') + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage'); +$storageareas = array('' => array('Name'=>'NULL Unspecified'), '0' => array('Name'=>'Zero')) + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage'); $weekdays = array(); for ( $i = 0; $i < 7; $i++ ) { diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 05914f911..94e132cc1 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -773,8 +773,9 @@ function manageDelConfirmModalBtns() { return; } + pauseClicked(); evt.preventDefault(); - $j.getJSON(thisUrl + '?request=event&task=delete&id='+eventData.Id) + $j.getJSON(thisUrl + '?request=event&action=delete&id='+eventData.Id) .done(function(data) { $j('#deleteConfirm').modal('hide'); streamNext(true); 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 + ''; diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index 787a910d0..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; @@ -985,6 +988,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 +1022,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)