From ac15ea42cd4d46968eda06269fd61841d8bf0fd0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Oct 2021 14:34:17 -0400 Subject: [PATCH 01/33] enforce default action --- utils/do_debian_package.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index 2a4dd6989..6c8c06c00 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -230,12 +230,11 @@ rm .gitignore cd ../ -if [ !-e "$DIRECTORY.orig.tar.gz" ]; then -read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]" - if [[ $REPLY == [yY] ]]; then - - tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig -fi; +if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then + read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]" + if [[ "$REPLY" == "" || "$REPLY" == [yY] ]]; then + tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig + fi; fi; IFS=',' ;for DISTRO in `echo "$DISTROS"`; do From f737e3e945403019ee01efe1d85d1fa0eb1a135b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 6 Nov 2021 09:58:31 -0400 Subject: [PATCH 02/33] Only list available ids if there are some --- web/skins/classic/views/monitor.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 68ce50397..e4b2754ab 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -461,9 +461,12 @@ switch ( $name ) {
-10 Available Ids: - - + + Date: Sun, 7 Nov 2021 11:28:34 -0500 Subject: [PATCH 03/33] Pretty up the v4l field names --- web/ajax/modals/settings.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/web/ajax/modals/settings.php b/web/ajax/modals/settings.php index de42d6c87..e0bdf679c 100644 --- a/web/ajax/modals/settings.php +++ b/web/ajax/modals/settings.php @@ -38,7 +38,7 @@ if ($zmuOutput) { $ctls = shell_exec('v4l2-ctl -d '.$monitor->Device().' --list-ctrls'); if (!$ctls) { -ZM\Warning("Guessing v4l ctrls. We need v4l2-ctl please install it"); +ZM\Warning('Guessing v4l ctrls. We need v4l2-ctl please install it'); $ctls = ' brightness 0x00980900 (int) : min=-10 max=10 step=1 default=0 value=8 contrast 0x00980901 (int) : min=0 max=20 step=1 default=10 value=12 @@ -83,10 +83,15 @@ foreach ($ctls as $line) { } } + $label = translate($setting_uc); + if ($label == $setting_uc) { + $label = ucwords(str_replace('_', ' ', $label)); + } + if ($setting == 'brightness' or $setting == 'colour' or $setting == 'contrast' or $setting == 'hue') { echo ' - '.translate($setting_uc).' + '.$label.' '.$min.''.$max.' '; @@ -94,7 +99,7 @@ foreach ($ctls as $line) { if ($type == '(bool)') { echo ' - '.translate($setting_uc).' + '.$label.' '.html_radio('new'.$setting_uc, array('0'=>translate('True'), '1', translate('False')), $value, array('disabled'=>'disabled')).' @@ -102,14 +107,14 @@ foreach ($ctls as $line) { } else if ($type == '(int)') { echo ' - '.translate($setting_uc).' + '.$label.' '; } else { echo ' - '.translate($setting_uc).' + '.$label.' '.$value.' '; From 8c2dec03b6371aac74cca902608ac1ec4b1c981a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 09:48:57 -0500 Subject: [PATCH 04/33] Default to now instead of ... epoch? when endtime is null. Fixes video playing when event is incomplete --- src/zm_eventstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 5e1ad605d..af9dd8639 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -141,7 +141,7 @@ bool EventStream::loadEventData(uint64_t event_id) { event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0; event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]); event_data->start_time = SystemTimePoint(Seconds(atoi(dbrow[3]))); - event_data->end_time = dbrow[4] ? SystemTimePoint(Seconds(atoi(dbrow[4]))) : SystemTimePoint(); + event_data->end_time = dbrow[4] ? SystemTimePoint(Seconds(atoi(dbrow[4]))) : std::chrono::system_clock::now(); event_data->duration = std::chrono::duration_cast(event_data->end_time - event_data->start_time); event_data->frames_duration = std::chrono::duration_cast(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0)); From ce81099489ccef7e3bfbadc35e792b479f057486 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:48:50 -0500 Subject: [PATCH 05/33] Report error if sql fails. Add check for access to specific event. --- web/ajax/events.php | 63 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 4e364242a..090fe476e 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -67,20 +67,19 @@ if (isset($_REQUEST['sort'])) { // Offset specifies the starting row to return, used for pagination $offset = 0; -if ( isset($_REQUEST['offset']) ) { - if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { +if (isset($_REQUEST['offset'])) { + if ((!is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']))) { ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); } else { $offset = $_REQUEST['offset']; } } - // Limit specifies the number of rows to return // Set the default to 0 for events view, to prevent an issue with ALL pagination $limit = 0; -if ( isset($_REQUEST['limit']) ) { - if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { +if (isset($_REQUEST['limit'])) { + if ((!is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']))) { ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); } else { $limit = $_REQUEST['limit']; @@ -91,25 +90,24 @@ if ( isset($_REQUEST['limit']) ) { // MAIN LOOP // -switch ( $task ) { +switch ($task) { case 'archive' : - foreach ( $eids as $eid ) archiveRequest($task, $eid); + foreach ($eids as $eid) archiveRequest($task, $eid); break; case 'unarchive' : # The idea is that anyone can archive, but only people with Event Edit permission can unarchive.. - if ( !canEdit('Events') ) { + if (!canEdit('Events')) { ajaxError('Insufficient permissions for user '.$user['Username']); return; } - foreach ( $eids as $eid ) archiveRequest($task, $eid); + foreach ($eids as $eid) archiveRequest($task, $eid); break; case 'delete' : - if ( !canEdit('Events') ) { + if (!canEdit('Events')) { ajaxError('Insufficient permissions for user '.$user['Username']); return; } - - foreach ( $eids as $eid ) $data[] = deleteRequest($eid); + foreach ($eids as $eid) $data[] = deleteRequest($eid); break; case 'query' : $data = queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit); @@ -139,6 +137,8 @@ function deleteRequest($eid) { $message[] = array($eid=>'Event not found.'); } else if ( $event->Archived() ) { $message[] = array($eid=>'Event is archived, cannot delete it.'); + } else if (!$event->canEdit()) { + $message[] = array($eid=>'You do not have permission to delete event '.$event->Id()); } else { $event->delete(); } @@ -147,7 +147,6 @@ function deleteRequest($eid) { } function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit) { - $data = array( 'total' => 0, 'totalNotFiltered' => 0, @@ -156,7 +155,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim ); $failed = !$filter->test_pre_sql_conditions(); - if ( $failed ) { + if ($failed) { ZM\Debug('Pre conditions failed, not doing sql'); return $data; } @@ -171,7 +170,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim // The names of columns shown in the event view that are NOT dB columns in the database $col_alt = array('Monitor', 'Storage'); - if ( !in_array($sort, array_merge($columns, $col_alt)) ) { + if (!in_array($sort, array_merge($columns, $col_alt))) { ZM\Error('Invalid sort field: ' . $sort); $sort = 'Id'; } @@ -186,7 +185,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $storage_areas = ZM\Storage::find(); $StorageById = array(); - foreach ( $storage_areas as $S ) { + foreach ($storage_areas as $S) { $StorageById[$S->Id()] = $S; } @@ -195,41 +194,43 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim ZM\Debug('Calling the following sql query: ' .$sql); $query = dbQuery($sql, $values); - if ( $query ) { - while ( $row = dbFetchNext($query) ) { - $event = new ZM\Event($row); - $event->remove_from_cache(); - if ( !$filter->test_post_sql_conditions($event) ) { - continue; - } - $event_ids[] = $event->Id(); - $unfiltered_rows[] = $row; - } # end foreach row + if (!$query) { + ajaxError(dbError($sql)); + return; } + while ($row = dbFetchNext($query)) { + $event = new ZM\Event($row); + $event->remove_from_cache(); + if (!$filter->test_post_sql_conditions($event)) { + continue; + } + $event_ids[] = $event->Id(); + $unfiltered_rows[] = $row; + } # end foreach row ZM\Debug('Have ' . count($unfiltered_rows) . ' events matching base filter.'); $filtered_rows = null; - if ( count($advsearch) or $search != '' ) { + if (count($advsearch) or $search != '') { $search_filter = new ZM\Filter(); $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$event_ids)); // There are two search bars in the log view, normal and advanced // Making an exuctive decision to ignore the normal search, when advanced search is in use // Alternatively we could try to do both - if ( count($advsearch) ) { + if (count($advsearch)) { $terms = array(); - foreach ( $advsearch as $col=>$text ) { + foreach ($advsearch as $col=>$text) { $terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text); } # end foreach col in advsearch $terms[0]['obr'] = 1; $terms[count($terms)-1]['cbr'] = 1; $search_filter->addTerms($terms); - } else if ( $search != '' ) { + } else if ($search != '') { $search = '%' .$search. '%'; $terms = array(); - foreach ( $columns as $col ) { + foreach ($columns as $col) { $terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search); } $terms[0]['obr'] = 1; From e617eb86152b25a44c82b8a168833eb630a3292e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:49:01 -0500 Subject: [PATCH 06/33] Whitespace --- web/includes/database.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/includes/database.php b/web/includes/database.php index 34ea384fa..01926a26e 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -112,7 +112,7 @@ function dbLog($sql, $update=false) { function dbError($sql) { global $dbConn; $error = $dbConn->errorInfo(); - if ( !$error[0] ) + if (!$error[0]) return ''; $message = "SQL-ERR '".implode("\n", $dbConn->errorInfo())."', statement was '".$sql."'"; @@ -130,17 +130,17 @@ function dbEscape( $string ) { function dbQuery($sql, $params=NULL, $debug = false) { global $dbConn; - if ( dbLog($sql, true) ) + if (dbLog($sql, true)) return; $result = NULL; try { - if ( isset($params) ) { - if ( ! $result = $dbConn->prepare($sql) ) { + if (isset($params)) { + if (!$result = $dbConn->prepare($sql)) { ZM\Error("SQL: Error preparing $sql: " . $pdo->errorInfo); return NULL; } - if ( ! $result->execute($params) ) { + if (!$result->execute($params)) { ZM\Error("SQL: Error executing $sql: " . print_r($result->errorInfo(), true)); return NULL; } From 7abbfc2fb54f8da9052baaab2c5107d2a0f5610d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:50:39 -0500 Subject: [PATCH 07/33] alert error message is an error is returned instead of rows --- web/skins/classic/views/js/events.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 9f6d34f75..6139ba3e4 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -35,12 +35,16 @@ var params = // Called by bootstrap-table to retrieve zm event data function ajaxRequest(params) { - if ( params.data && params.data.filter ) { + if (params.data && params.data.filter) { params.data.advsearch = params.data.filter; delete params.data.filter; } $j.getJSON(thisUrl + '?view=request&request=events&task=query'+filterQuery, params.data) .done(function(data) { + if (data.result == 'Error') { + alert(data.message); + return; + } var rows = processRows(data.rows); // rearrange the result into what bootstrap-table expects params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows}); From 7aefd657c75b51a6e7c828d1e384ae23306639f7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:51:32 -0500 Subject: [PATCH 08/33] Cleanup and spacing. Rework last_motion_score to be a bit more efficient and use fewer lines. Fix case where MOCORD was not ending/starting event on alarm. --- src/zm_monitor.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 679ea27b7..cdf544682 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1862,8 +1862,6 @@ bool Monitor::Analyse() { Debug(3, "signal and active and modect"); Event::StringSet zoneSet; - int motion_score = last_motion_score; - if (analysis_fps_limit) { double capture_fps = get_capture_fps(); motion_frame_skip = capture_fps / analysis_fps_limit; @@ -1880,7 +1878,7 @@ bool Monitor::Analyse() { } else { Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image); // Get new score. - motion_score = DetectMotion(*(snap->image), zoneSet); + int motion_score = DetectMotion(*(snap->image), zoneSet); snap->zone_stats.reserve(zones.size()); for (const Zone &zone : zones) { @@ -1892,21 +1890,20 @@ bool Monitor::Analyse() { Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)", score, last_motion_score, motion_score); motion_frame_count += 1; - // Why are we updating the last_motion_score too? last_motion_score = motion_score; + if (motion_score) { + if (cause.length()) cause += ", "; + cause += MOTION_CAUSE; + noteSetMap[MOTION_CAUSE] = zoneSet; + } // end if motion_score } } else { Debug(1, "no image so skipping motion detection"); } // end if has image } else { - Debug(1, "Skipped motion detection last motion score was %d", motion_score); + Debug(1, "Skipped motion detection last motion score was %d", last_motion_score); } - if (motion_score) { - score += motion_score; - if (cause.length()) cause += ", "; - cause += MOTION_CAUSE; - noteSetMap[MOTION_CAUSE] = zoneSet; - } // end if motion_score + score += last_motion_score; } else { Debug(1, "Not Active(%d) enabled %d active %d doing motion detection: %d", Active(), enabled, shared_data->active, @@ -2007,7 +2004,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function == MODECT or function == NODECT)) { + if (score and (function == MODECT or function == NODECT or function == MOCORD)) { if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) { // If we should end then previous continuous event and start a new non-continuous event if (event && event->Frames() @@ -2142,7 +2139,8 @@ bool Monitor::Analyse() { shared_data->state = state = ((function != MOCORD) ? IDLE : TAPE); } else { Debug(1, - "State %s because image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + "State %d %s because analysis_image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + state, State_Strings[state].c_str(), analysis_image_count, last_alarm_count, @@ -2161,12 +2159,10 @@ bool Monitor::Analyse() { // Generate analysis images if necessary if ((savejpegs > 1) and snap->image) { for (const Zone &zone : zones) { - if (zone.Alarmed()) { - if (zone.AlarmImage()) { + if (zone.Alarmed() and zone.AlarmImage()) { if (!snap->analysis_image) snap->analysis_image = new Image(*(snap->image)); snap->analysis_image->Overlay(*(zone.AlarmImage())); - } } // end if zone is alarmed } // end foreach zone } // end if savejpegs From 38105c67968bb1c38b8bd24ed3308673f40ba96d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:54:33 -0500 Subject: [PATCH 09/33] Spacing --- src/zm_event.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 442033c50..d52f606a6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -323,32 +323,32 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) { bool update = false; //Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() ); - if ( newNoteSetMap.size() > 0 ) { - if ( noteSetMap.size() == 0 ) { + if (newNoteSetMap.size() > 0) { + if (noteSetMap.size() == 0) { noteSetMap = newNoteSetMap; update = true; } else { - for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); + for (StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); - ++newNoteSetMapIter ) { + ++newNoteSetMapIter) { const std::string &newNoteGroup = newNoteSetMapIter->first; const StringSet &newNoteSet = newNoteSetMapIter->second; //Info( "Got %d new strings", newNoteSet.size() ); - if ( newNoteSet.size() > 0 ) { + if (newNoteSet.size() > 0) { StringSetMap::iterator noteSetMapIter = noteSetMap.find(newNoteGroup); - if ( noteSetMapIter == noteSetMap.end() ) { - //Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() ); + if (noteSetMapIter == noteSetMap.end()) { + //Debug(3, "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size()); noteSetMap.insert(StringSetMap::value_type(newNoteGroup, newNoteSet)); update = true; } else { StringSet ¬eSet = noteSetMapIter->second; - //Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() ); - for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); + //Debug(3, "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size()); + for (StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); - ++newNoteSetIter ) { + ++newNoteSetIter) { const std::string &newNote = *newNoteSetIter; StringSet::iterator noteSetIter = noteSet.find(newNote); - if ( noteSetIter == noteSet.end() ) { + if (noteSetIter == noteSet.end()) { noteSet.insert(newNote); update = true; } From 5d23362ae02ca61ae4b8d3e5f62f81cb9ee7f8ce Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:59:05 -0500 Subject: [PATCH 10/33] use != Monitor instead of all the other cases --- src/zm_monitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index cdf544682..81eacc956 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2004,7 +2004,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function == MODECT or function == NODECT or function == MOCORD)) { + if (score and (function != MONITOR)) { if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) { // If we should end then previous continuous event and start a new non-continuous event if (event && event->Frames() From 66517218f1094ef22dad87abdec0f3878ac7092d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 14:00:04 -0500 Subject: [PATCH 11/33] Ignore versioned bootstrap --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 4682851df..91b0fd196 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,7 @@ web/api/lib web/includes/csrf/ web/js/videojs.zoomrotate.js -web/skins/classic/js/bootstrap.js +web/skins/classic/js/bootstrap-4.5.0.js web/skins/classic/js/chosen web/skins/classic/js/dateTimePicker web/skins/classic/js/jquery-*.js From 508be72e08cbfef15508208a0028c7fb97a31bf4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 15:49:25 -0500 Subject: [PATCH 12/33] Don't exit(0) on QUIT. Instead set zm_terminate=true so that all the cleanup routines run. --- src/zm_monitorstream.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 5c32b8e05..9bc04a311 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -229,6 +229,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) { break; case CMD_QUIT : Info("User initiated exit - CMD_QUIT"); + zm_terminate = true; break; case CMD_QUERY : Debug(1, "Got QUERY command, sending STATUS"); @@ -315,16 +316,6 @@ void MonitorStream::processCommand(const CmdMsg *msg) { } } Debug(2, "Number of bytes sent to (%s): (%d)", rem_addr.sun_path, nbytes); - - // quit after sending a status, if this was a quit request - if ( (MsgCommand)msg->msg_data[0] == CMD_QUIT ) { - zm_terminate = true; - Debug(2, "Quitting"); - return; - } - - //Debug(2,"Updating framerate"); - //updateFrameRate(monitor->GetFPS()); } // end void MonitorStream::processCommand(const CmdMsg *msg) bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint timestamp) { From 30d4900b45a56974614fc42cf5538311efb01cf1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 14:32:06 -0500 Subject: [PATCH 13/33] rough in fullscreen mode in watch view --- web/skins/classic/js/skin.js | 26 ++++++++++++++++++++++++++ web/skins/classic/views/js/watch.js | 5 +++++ web/skins/classic/views/watch.php | 3 +++ 3 files changed, 34 insertions(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index c7e2afedf..6ede08479 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -947,3 +947,29 @@ function initThumbAnimation() { }); } } + +/* View in fullscreen */ +function openFullscreen(elem) { + if (elem.requestFullscreen) { + elem.requestFullscreen(); + } else if (elem.webkitRequestFullscreen) { + /* Safari */ + elem.webkitRequestFullscreen(); + } else if (elem.msRequestFullscreen) { + /* IE11 */ + elem.msRequestFullscreen(); + } +} + +/* Close fullscreen */ +function closeFullscreen() { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + /* Safari */ + document.webkitExitFullscreen(); + } else if (document.msExitFullscreen) { + /* IE11 */ + document.msExitFullscreen(); + } +} diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index aacad5126..5ba4b407c 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -970,5 +970,10 @@ function initPage() { }); } // initPage +function watchFullscreen() { + const content = document.getElementById('content'); + openFullscreen(content); +} + // Kick everything off $j(document).ready(initPage); diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index e1e54c3c7..beab28ac1 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -142,6 +142,9 @@ if ( $streamMode == 'jpeg' ) { + From f263da89867c4db9fab4deaf461894c15673190b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 16:12:39 -0500 Subject: [PATCH 14/33] Rough in fullscreen mode on montage --- web/skins/classic/views/js/montage.js | 5 +++++ web/skins/classic/views/montage.php | 3 +++ 2 files changed, 8 insertions(+) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 5312928a6..75b3a74d2 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -317,5 +317,10 @@ function initPage() { } selectLayout('#zmMontageLayout'); } + +function watchFullscreen() { + const content = document.getElementById('content'); + openFullscreen(content); +} // Kick everything off $j(document).ready(initPage); diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index 3256cfcc8..b0b10f190 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -206,6 +206,9 @@ if ( canView('System') ) {   + From 44d88edbbbcbbd43ac6dcf7b35f8af7f2203d370 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 17:01:04 -0500 Subject: [PATCH 15/33] Fix some build warnings on arm --- src/zm_fifo.cpp | 4 ++-- src/zm_monitor.cpp | 22 +++++++++++----------- src/zm_packetqueue.cpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index 319c35c31..a999adc23 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -143,8 +143,8 @@ bool Fifo::writePacket(std::string filename, const ZMPacket &packet) { bool Fifo::write(uint8_t *data, size_t bytes, int64_t pts) { if (!(outfile or open())) return false; // Going to write a brief header - Debug(1, "Writing header ZM %lu %" PRId64, bytes, pts); - if ( fprintf(outfile, "ZM %lu %" PRId64 "\n", bytes, pts) < 0 ) { + Debug(1, "Writing header ZM %zu %" PRId64, bytes, pts); + if (fprintf(outfile, "ZM %zu %" PRId64 "\n", bytes, pts) < 0) { if (errno != EAGAIN) { Error("Problem during writing: %s", strerror(errno)); } else { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 81eacc956..b6e69a19f 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -155,7 +155,7 @@ bool Monitor::MonitorLink::connect() { mem_size = sizeof(SharedData) + sizeof(TriggerData); - Debug(1, "link.mem.size=%jd", mem_size); + Debug(1, "link.mem.size=%jd", static_cast(mem_size)); #if ZM_MEM_MAPPED map_fd = open(mem_file.c_str(), O_RDWR, (mode_t)0600); if (map_fd < 0) { @@ -182,14 +182,14 @@ bool Monitor::MonitorLink::connect() { disconnect(); return false; } else if (map_stat.st_size < mem_size) { - Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, mem_size); + Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, static_cast(mem_size)); disconnect(); return false; } mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); if (mem_ptr == MAP_FAILED) { - Error("Can't map file %s (%jd bytes) to memory: %s", mem_file.c_str(), mem_size, strerror(errno)); + Error("Can't map file %s (%jd bytes) to memory: %s", mem_file.c_str(), static_cast(mem_size), strerror(errno)); disconnect(); return false; } @@ -947,7 +947,7 @@ bool Monitor::connect() { map_fd = -1; return false; } else { - Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, mem_size); + Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, static_cast(mem_size)); close(map_fd); map_fd = -1; return false; @@ -959,18 +959,18 @@ bool Monitor::connect() { mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0); if (mem_ptr == MAP_FAILED) { if (errno == EAGAIN) { - Debug(1, "Unable to map file %s (%jd bytes) to locked memory, trying unlocked", mem_file.c_str(), mem_size); + Debug(1, "Unable to map file %s (%jd bytes) to locked memory, trying unlocked", mem_file.c_str(), static_cast(mem_size)); #endif mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); - Debug(1, "Mapped file %s (%jd bytes) to unlocked memory", mem_file.c_str(), mem_size); + Debug(1, "Mapped file %s (%jd bytes) to unlocked memory", mem_file.c_str(), static_cast(mem_size)); #ifdef MAP_LOCKED } else { - Error("Unable to map file %s (%jd bytes) to locked memory (%s)", mem_file.c_str(), mem_size, strerror(errno)); + Error("Unable to map file %s (%jd bytes) to locked memory (%s)", mem_file.c_str(), static_cast(mem_size), strerror(errno)); } } #endif if ((mem_ptr == MAP_FAILED) or (mem_ptr == nullptr)) { - Error("Can't map file %s (%jd bytes) to memory: %s(%d)", mem_file.c_str(), mem_size, strerror(errno), errno); + Error("Can't map file %s (%jd bytes) to memory: %s(%d)", mem_file.c_str(), static_cast(mem_size), strerror(errno), errno); close(map_fd); map_fd = -1; mem_ptr = nullptr; @@ -2310,7 +2310,7 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { while ( 1 ) { dest_ptr = link_id_str; while ( *src_ptr >= '0' && *src_ptr <= '9' ) { - if ( (dest_ptr-link_id_str) < (unsigned int)(sizeof(link_id_str)-1) ) { + if ( (unsigned int)(dest_ptr-link_id_str) < (unsigned int)(sizeof(link_id_str)-1) ) { *dest_ptr++ = *src_ptr++; } else { break; @@ -2741,7 +2741,7 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const { const char *s_ptr = label_time_text; char *d_ptr = label_text; - while (*s_ptr && ((d_ptr - label_text) < (unsigned int) sizeof(label_text))) { + while (*s_ptr && ((unsigned int)(d_ptr - label_text) < (unsigned int) sizeof(label_text))) { if ( *s_ptr == config.timestamp_code_char[0] ) { bool found_macro = false; switch ( *(s_ptr+1) ) { @@ -2757,7 +2757,7 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const { typedef std::chrono::duration Centiseconds; Centiseconds centi_sec = std::chrono::duration_cast( ts_time.time_since_epoch() - std::chrono::duration_cast(ts_time.time_since_epoch())); - d_ptr += snprintf(d_ptr, sizeof(label_text) - (d_ptr - label_text), "%02ld", centi_sec.count()); + d_ptr += snprintf(d_ptr, sizeof(label_text) - (d_ptr - label_text), "%02lld", static_cast(centi_sec.count())); found_macro = true; break; } diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index ceef421db..509a25ee6 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -209,7 +209,7 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { --it; } } - Debug(1, "Tail count is %d, queue size is %lu", tail_count, pktQueue.size()); + Debug(1, "Tail count is %d, queue size is %zu", tail_count, pktQueue.size()); if (!keep_keyframes) { // If not doing passthrough, we don't care about starting with a keyframe so logic is simpler From 4c2d50c1f422a915f706b010aceda467f3afb667 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:18:58 -0500 Subject: [PATCH 16/33] implement UrlToZMS in Monitor --- web/includes/Monitor.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 027cafadd..788486b2e 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -495,6 +495,10 @@ class Monitor extends ZM_Object { return $this->Server()->UrlToIndex($port); } + public function UrlToZMS($port=null) { + return $this->Server()->UrlToZMS($port).'?mid='.$this->Id(); + } + public function sendControlCommand($command) { // command is generally a command option list like --command=blah but might be just the word quit From 474f65cff36354c5960e32070ae1d80d6a985556 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:20:19 -0500 Subject: [PATCH 17/33] Implement getElement, setScale in MonitorStream.js --- web/js/MonitorStream.js | 75 ++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index a10d90008..feb4b3611 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -3,8 +3,10 @@ function MonitorStream(monitorData) { this.id = monitorData.id; this.connKey = monitorData.connKey; this.url = monitorData.url; + this.url_to_zms = monitorData.url_to_zms; this.width = monitorData.width; this.height = monitorData.height; + this.scale = 100; this.status = null; this.alarmState = STATE_IDLE; this.lastAlarmState = STATE_IDLE; @@ -15,19 +17,68 @@ function MonitorStream(monitorData) { }; this.type = monitorData.type; this.refresh = monitorData.refresh; + this.element = null; + this.getElement = function() { + if (this.element) return this.element; + this.element = document.getElementById('liveStream'+this.id); + if (!this.element) { + console.error("No img for #liveStream"+this.id); + } + return this.element; + }; + + /* if the img element didn't have a src, this would fill it in, causing it to show. */ + this.show = function() { + const stream = this.getElement(); + if (!stream.src) { + stream.src = this.url_to_zms+"&mode=single&scale=100&connkey="+this.connKey; + } + }; + + this.setScale = function(newscale) { + const img = this.getElement(); + if (!img) return; + + this.scale = newscale; + + const oldSrc = img.getAttribute('src'); + let newSrc = ''; + + img.setAttribute('src', ''); + console.log("Scaling to: " + newscale); + + if (newscale == '0' || newscale == 'auto') { + let bottomElement = document.getElementById('replayStatus'); + if (!bottomElement) { + bottomElement = document.getElementById('monitorState'); + } + var newSize = scaleToFit(this.width, this.height, $j(img), $j(bottomElement)); + + console.log(newSize); + newWidth = newSize.width; + newHeight = newSize.height; + autoScale = parseInt(newSize.autoScale); + // This is so that we don't waste bandwidth and let the browser do all the scaling. + if (autoScale > 100) autoScale = 100; + if (autoScale) { + newSrc = oldSrc.replace(/scale=\d+/i, 'scale='+autoScale); + } + } else { + newWidth = this.width * newscale / SCALE_BASE; + newHeight = this.height * newscale / SCALE_BASE; + img.width(newWidth); + img.height(newHeight); + if (newscale > 100) newscale = 100; + newSrc = oldSrc.replace(/scale=\d+/i, 'scale='+newscale); + } + img.setAttribute('src', newSrc); + }; this.start = function(delay) { // Step 1 make sure we are streaming instead of a static image - var stream = $j('#liveStream'+this.id); - if (!stream.length) { - console.log('No live stream'); - return; - } - stream = stream[0]; - if ( !stream ) { - console.log('No live stream'); - return; - } - if ( !stream.src ) { + const stream = this.getElement(); + if (!stream) return; + + if (!stream.src) { // Website Monitors won't have an img tag console.log('No src for #liveStream'+this.id); console.log(stream); @@ -38,7 +89,7 @@ function MonitorStream(monitorData) { src += '&connkey='+this.connKey; } if ( stream.src != src ) { - console.log("Setting to streaming"); + console.log("Setting to streaming: " + src); stream.src = ''; stream.src = src; } From b8f6172110ddee1ade30cdb0474d301ff01eb197 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:21:12 -0500 Subject: [PATCH 18/33] If no bottom element is specified, take the last child of content in scaleToFit --- web/skins/classic/js/skin.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 6ede08479..a12005e76 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -584,10 +584,21 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { $j(window).on('resize', endOfResize); //set delayed scaling when Scale to Fit is selected var ratio = baseWidth / baseHeight; var container = $j('#content'); + if (!container) { + console.error("No container found"); + return; + } + + if (!bottomEl || !bottomEl.length) { + bottomEl = $j(container[0].lastElementChild); + } + //console.log(bottomEl); var viewPort = $j(window); - // jquery does not provide a bottom offet, and offset dows not include margins. outerHeight true minus false gives total vertical margins. + // jquery does not provide a bottom offset, and offset does not include margins. outerHeight true minus false gives total vertical margins. var bottomLoc = bottomEl.offset().top + (bottomEl.outerHeight(true) - bottomEl.outerHeight()) + bottomEl.outerHeight(true); + //console.log("bottomLoc: " + bottomEl.offset().top + " + (" + bottomEl.outerHeight(true) + ' - ' + bottomEl.outerHeight() +') + '+bottomEl.outerHeight(true)); var newHeight = viewPort.height() - (bottomLoc - scaleEl.outerHeight(true)); + //console.log("newHeight = " + viewPort.height() +" - " + bottomLoc + ' - ' + scaleEl.outerHeight(true)); var newWidth = ratio * newHeight; if (newWidth > container.innerWidth()) { newWidth = container.innerWidth(); @@ -598,13 +609,15 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { return parseInt($j(this).val()); }).get(); scales.shift(); - var closest; + var closest = null; $j(scales).each(function() { //Set zms scale to nearest regular scale. Zoom does not like arbitrary scale values. if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) { closest = this.valueOf(); } }); - autoScale = closest; + if (closest) { + autoScale = closest; + } return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale}; } From 43c188626705adcbdde54d771242d030e13fd941 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:21:38 -0500 Subject: [PATCH 19/33] Put SCALE_BASE in skin.js.php as it is used in many places. --- web/skins/classic/js/skin.js.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/js/skin.js.php b/web/skins/classic/js/skin.js.php index 802a21095..87e08310e 100644 --- a/web/skins/classic/js/skin.js.php +++ b/web/skins/classic/js/skin.js.php @@ -54,6 +54,7 @@ foreach ( $perms as $perm ) { ?> var ANIMATE_THUMBS = ; +var SCALE_BASE = ; var refreshParent = Date: Wed, 10 Nov 2021 14:22:05 -0500 Subject: [PATCH 20/33] Implement Exit Fullscreen using same button --- web/skins/classic/views/js/watch.js | 14 ++++++++++++-- web/skins/classic/views/js/watch.js.php | 6 +++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 5ba4b407c..324e7f7e0 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -971,8 +971,18 @@ function initPage() { } // initPage function watchFullscreen() { - const content = document.getElementById('content'); - openFullscreen(content); + const btn = document.getElementById('fullscreenBtn'); + console.log(btn); + if (btn.firstElementChild.innerHTML=='fullscreen') { + const content = document.getElementById('content'); + openFullscreen(content); + btn.firstElementChild.innerHTML='fullscreen_exit'; + btn.setAttribute('title', translate["Exit Fullscreen"]); + } else { + closeFullscreen(); + btn.firstElementChild.innerHTML='fullscreen'; + btn.setAttribute('title', translate["Fullscreen"]); + } } // Kick everything off diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index 258a1da73..5b4568dfc 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -97,9 +97,13 @@ foreach( dbFetchAll( 'SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, a $labels[$row['Preset']] = $row['Label']; } -foreach ( $labels as $index=>$label ) { +foreach ($labels as $index=>$label) { ?> labels[] = ''; +var translate = { + "Fullscreen": "", + "Exit Fullscreen": "", +}; From ed84b5967156572ab4e26240ddcb5de2f9d39358 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:23:36 -0500 Subject: [PATCH 21/33] remove extra , --- web/ajax/event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 906fe255a..a0b9cb57a 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -93,7 +93,7 @@ if ( canView('Events') or canView('Snapshots') ) { $exportFormat, $exportCompress, $exportStructure, - (!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport'), + (!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport') )) { ajaxResponse(array('exportFile'=>$exportFile)); } else { From 377219befea0ae4876c3367adb4d794126e3ede2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:12 -0500 Subject: [PATCH 22/33] Include url_to_zms in monitorData --- web/skins/classic/views/js/zone.js.php | 1 + web/skins/classic/views/js/zones.js.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/zone.js.php b/web/skins/classic/views/js/zone.js.php index fc6616327..37eb6db82 100644 --- a/web/skins/classic/views/js/zone.js.php +++ b/web/skins/classic/views/js/zone.js.php @@ -66,6 +66,7 @@ monitorData[monitorData.length] = { 'width': ViewWidth() ?>, 'height':ViewHeight() ?>, 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'url_to_zms': 'UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', 'type': 'Type() ?>', 'refresh': 'Refresh() ?>' }; diff --git a/web/skins/classic/views/js/zones.js.php b/web/skins/classic/views/js/zones.js.php index 180a19d81..338095552 100644 --- a/web/skins/classic/views/js/zones.js.php +++ b/web/skins/classic/views/js/zones.js.php @@ -9,6 +9,7 @@ monitorData[monitorData.length] = { 'width': ViewWidth() ?>, 'height':ViewHeight() ?>, 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'url_to_zms': 'UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', 'type': 'Type() ?>', 'refresh': 'Refresh() ?>' }; @@ -24,7 +25,7 @@ var STATE_TAPE = ; var stateStrings = new Array(); stateStrings[STATE_IDLE] = ""; -stateStrings[STATE_PREALARM] = ""; +stateStrings[STATE_PREALARM] = ""; stateStrings[STATE_ALARM] = ""; stateStrings[STATE_ALERT] = ""; stateStrings[STATE_TAPE] = ""; From 0732d4c1b3bd694ab6cb287ba70419b24686e914 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:29 -0500 Subject: [PATCH 23/33] setScale to auto --- web/skins/classic/views/js/zone.js | 1 + web/skins/classic/views/js/zones.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index 6282cbf8a..58c286b43 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -661,6 +661,7 @@ function initPage() { // Start the fps and status updates. give a random delay so that we don't assault the server var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); + monitors[i].setScale('auto'); monitors[i].start(delay); } diff --git a/web/skins/classic/views/js/zones.js b/web/skins/classic/views/js/zones.js index 0ad91942d..67dcb094a 100644 --- a/web/skins/classic/views/js/zones.js +++ b/web/skins/classic/views/js/zones.js @@ -12,6 +12,7 @@ function initPage() { // Start the fps and status updates. give a random delay so that we don't assault the server var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); + monitors[i].setScale('auto'); monitors[i].start(delay); } @@ -31,5 +32,12 @@ function initPage() { }); } +function streamCmdQuit() { + for ( var i = 0, length = monitorData.length; i < length; i++ ) { + monitors[i] = new MonitorStream(monitorData[i]); + monitors[i].stop(); + } +} + window.addEventListener('DOMContentLoaded', initPage); From 2c0c257d76284b77277ef2941aef8e82b0e8a290 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:45 -0500 Subject: [PATCH 24/33] spacing --- web/skins/classic/views/zones.php | 67 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/web/skins/classic/views/zones.php b/web/skins/classic/views/zones.php index f457ad2fc..423326a98 100644 --- a/web/skins/classic/views/zones.php +++ b/web/skins/classic/views/zones.php @@ -80,15 +80,14 @@ xhtmlHeaders(__FILE__, translate('Zones')); Sorry, your browser does not support inline SVG @@ -96,37 +95,37 @@ xhtmlHeaders(__FILE__, translate('Zones'));  -  fps -
- - - - - - - - - - - - - - - - - - - -
 / ViewWidth()*$monitor->ViewHeight()) ) ?> disabled="disabled"/>
-
- - -
-
-
+
+ + + + + + + + + + + + + + + + + + + +
 / ViewWidth()*$monitor->ViewHeight()) ) ?> disabled="disabled"/>
+
+ + +
+
+
Date: Wed, 10 Nov 2021 16:53:07 -0500 Subject: [PATCH 25/33] Use event->StartTime instead of GetVideoWriterStartTime. Add some parenthesis to make logic clearer and add more info to debug statements --- src/zm_monitor.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index b6e69a19f..d808ddba0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1916,7 +1916,7 @@ bool Monitor::Analyse() { if (event) { Debug(2, "Have event %" PRIu64 " in record", event->Id()); - if (section_length != Seconds(0) && (timestamp - GetVideoWriterStartTime() >= section_length) + if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length) && ((function == MOCORD && event_close_mode != CLOSE_TIME) || (function == RECORD && event_close_mode == CLOSE_TIME) || std::chrono::duration_cast(timestamp.time_since_epoch()) % section_length == Seconds(0))) { @@ -1925,8 +1925,8 @@ bool Monitor::Analyse() { image_count, event->Id(), static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), - static_cast(std::chrono::duration_cast(GetVideoWriterStartTime().time_since_epoch()).count()), - static_cast(std::chrono::duration_cast(timestamp - GetVideoWriterStartTime()).count()), + static_cast(std::chrono::duration_cast(event->StartTime().time_since_epoch()).count()), + static_cast(std::chrono::duration_cast(timestamp - event->StartTime()).count()), static_cast(Seconds(section_length).count())); closeEvent(); } // end if section_length @@ -2009,21 +2009,22 @@ bool Monitor::Analyse() { // If we should end then previous continuous event and start a new non-continuous event if (event && event->Frames() && !event->AlarmFrames() - && event_close_mode == CLOSE_ALARM - && timestamp - GetVideoWriterStartTime() >= min_section_length - && (!pre_event_count || Event::PreAlarmCount() >= alarm_frame_count - 1)) { + && (event_close_mode == CLOSE_ALARM) + && ((timestamp - event->StartTime()) >= min_section_length) + && ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count - 1))) { Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins", name.c_str(), image_count, event->Id()); closeEvent(); } else if (event) { // This is so if we need more than 1 alarm frame before going into alarm, so it is basically if we have enough alarm frames Debug(3, - "pre_alarm_count in event %d, event frames %d, alarm frames %d event length %" PRIi64 " >=? %" PRIi64 " min", - Event::PreAlarmCount(), + "pre_alarm_count in event %d of %d, event frames %d, alarm frames %d event length %" PRIi64 " >=? %" PRIi64 " min close mode is ALARM? %d", + Event::PreAlarmCount(), pre_event_count, event->Frames(), event->AlarmFrames(), - static_cast(std::chrono::duration_cast(timestamp - GetVideoWriterStartTime()).count()), - static_cast(Seconds(min_section_length).count())); + static_cast(std::chrono::duration_cast(timestamp - event->StartTime()).count()), + static_cast(Seconds(min_section_length).count()), + (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 @@ -2120,8 +2121,10 @@ bool Monitor::Analyse() { Info("%s: %03d - Gone into alert state", name.c_str(), analysis_image_count); shared_data->state = state = ALERT; } else if (state == ALERT) { - if (analysis_image_count - last_alarm_count > post_event_count - && timestamp - GetVideoWriterStartTime() >= min_section_length) { + if ( + ((analysis_image_count - last_alarm_count) > post_event_count) + && + ((timestamp - event->StartTime()) >= min_section_length)) { Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name.c_str(), analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames()); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) @@ -2168,7 +2171,6 @@ bool Monitor::Analyse() { } // end if savejpegs // incremement pre alarm image count - //have_pre_alarmed_frames ++; Event::AddPreAlarmFrame(snap->image, timestamp, score, nullptr); } else if (state == ALARM) { for (const Zone &zone : zones) { @@ -2183,7 +2185,7 @@ bool Monitor::Analyse() { if (event) { if (noteSetMap.size() > 0) event->updateNotes(noteSetMap); - if (section_length != Seconds(0) && (timestamp - GetVideoWriterStartTime() >= section_length)) { + if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length)) { Warning("%s: %03d - event %" PRIu64 ", has exceeded desired section length. %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64, name.c_str(), analysis_image_count, event->Id(), static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), From 8d85d0f6402d43959e223234f798a969512af16e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 16:53:29 -0500 Subject: [PATCH 26/33] Make state enum start at 0 as we are indexing into an array for StateStrings --- src/zm_monitor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 56785405f..5b9a2ce46 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -100,7 +100,7 @@ public: } Deinterlace; typedef enum { - UNKNOWN=-1, + UNKNOWN, IDLE, PREALARM, ALARM, From 721769993b746f04f0205ca6fe854574dff855c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 17:05:46 -0500 Subject: [PATCH 27/33] Set to never timeout while generating video --- web/skins/classic/views/js/video.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/skins/classic/views/js/video.js b/web/skins/classic/views/js/video.js index 970119f4f..c764f33b5 100644 --- a/web/skins/classic/views/js/video.js +++ b/web/skins/classic/views/js/video.js @@ -16,6 +16,9 @@ function generateVideoResponse( data, responseText ) { } function generateVideo() { + $j.ajaxSetup({ + timeout: 0 + }); var form = $j('#videoForm').serialize(); $j.getJSON(thisUrl + '?view=request&request=event&action=video', form) .done(generateVideoResponse) From 6cd1f6b5f3286af43b1c1b3d09a6e953693c2914 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 13:50:18 -0500 Subject: [PATCH 28/33] Fix memleak on event creation due to not freeing storage object --- src/zm_event.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index d52f606a6..aad16a767 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -103,7 +103,7 @@ Event::Event( // Copy it in case opening the mp4 doesn't work we can set it to another value save_jpegs = monitor->GetOptSaveJPEGs(); - Storage * storage = monitor->getStorage(); + Storage *storage = monitor->getStorage(); if (monitor->GetOptVideoWriter() != 0) { container = monitor->OutputContainer(); if ( container == "auto" || container == "" ) { @@ -133,22 +133,22 @@ Event::Event( ); id = zmDbDoInsert(sql); - if ( !SetPath(storage) ) { + if (!SetPath(storage)) { // Try another Warning("Failed creating event dir at %s", storage->Path()); sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id()); - if ( monitor->ServerId() ) + if (monitor->ServerId()) sql += stringtf(" AND ServerId=%u", monitor->ServerId()); - Debug(1, "%s", sql.c_str()); + delete storage; storage = nullptr; MYSQL_RES *result = zmDbFetch(sql); - if ( result ) { - for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + if (result) { + for (int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) { storage = new Storage(atoi(dbrow[0])); - if ( SetPath(storage) ) + if (SetPath(storage)) break; delete storage; storage = nullptr; @@ -156,18 +156,18 @@ Event::Event( mysql_free_result(result); result = nullptr; } - if ( !storage ) { + if (!storage) { Info("No valid local storage area found. Trying all other areas."); // Try remote sql = "SELECT `Id` FROM `Storage` WHERE ServerId IS NULL"; - if ( monitor->ServerId() ) + if (monitor->ServerId()) sql += stringtf(" OR ServerId != %u", monitor->ServerId()); result = zmDbFetch(sql); - if ( result ) { + if (result) { for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { storage = new Storage(atoi(dbrow[0])); - if ( SetPath(storage) ) + if (SetPath(storage)) break; delete storage; storage = nullptr; @@ -176,7 +176,7 @@ Event::Event( result = nullptr; } } - if ( !storage ) { + if (!storage) { storage = new Storage(); Warning("Failed to find a storage area to save events."); } @@ -218,6 +218,7 @@ Event::Event( Debug(1, "Video file is %s", video_file.c_str()); } } // end if GetOptVideoWriter + delete storage; } Event::~Event() { From 883772295d263b41044c41fe39020937f9212759 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 13:51:17 -0500 Subject: [PATCH 29/33] spacing and log the new log level string as well as number --- src/zm_logger.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 5c7c5e9a7..f43ea6f30 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -43,11 +43,11 @@ Logger::IntMap Logger::smSyslogPriorities; void Logger::usrHandler(int sig) { Logger *logger = fetch(); - if ( sig == SIGUSR1 ) + if (sig == SIGUSR1) logger->level(logger->level()+1); - else if ( sig == SIGUSR2 ) + else if (sig == SIGUSR2) logger->level(logger->level()-1); - Info("Logger - Level changed to %d", logger->level()); + Info("Logger - Level changed to %d %s", logger->level(), smCodes[logger->level()].c_str()); } Logger::Logger() : @@ -296,23 +296,23 @@ const std::string &Logger::id(const std::string &id) { } Logger::Level Logger::level(Logger::Level level) { - if ( level > NOOPT ) { + if (level > NOOPT) { mLevel = limit(level); mEffectiveLevel = NOLOG; - if ( mTerminalLevel > mEffectiveLevel ) + if (mTerminalLevel > mEffectiveLevel) mEffectiveLevel = mTerminalLevel; - if ( mDatabaseLevel > mEffectiveLevel ) + if (mDatabaseLevel > mEffectiveLevel) mEffectiveLevel = mDatabaseLevel; - if ( mFileLevel > mEffectiveLevel ) + if (mFileLevel > mEffectiveLevel) mEffectiveLevel = mFileLevel; - if ( mSyslogLevel > mEffectiveLevel ) + if (mSyslogLevel > mEffectiveLevel) mEffectiveLevel = mSyslogLevel; - if ( mEffectiveLevel > mLevel) + if (mEffectiveLevel > mLevel) mEffectiveLevel = mLevel; // DEBUG levels should flush - if ( mLevel > INFO ) + if (mLevel > INFO) mFlush = true; } return mLevel; From a0215067e4ecaf0ccf3d7f7a370f0bb7ec4db01d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 13:58:52 -0500 Subject: [PATCH 30/33] In multi-server when viewing an event it may be coming from a different server than the serverhost. Use monitorUrl instead of thisUrl in ajax calls and include auth data. Fixes failed ajax when viewing h264 using zms on a multi-server environment --- web/skins/classic/views/js/event.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 050a78d59..1c4f72404 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -34,7 +34,7 @@ function streamReq(data) { data.view = 'request'; data.request = 'stream'; - $j.getJSON(thisUrl, data) + $j.getJSON(monitorUrl, data) .done(getCmdResponse) .fail(logAjaxFail); } @@ -657,6 +657,7 @@ function getFrameResponse(respObj, respText) { function frameQuery(eventId, frameId, loadImage) { var data = {}; + if (auth_hash) data.auth = auth_hash; data.loopback = loadImage; data.id = {eventId, frameId}; From 036d47a832383353b37af3d148dd86ff13a5e99c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 14:42:08 -0500 Subject: [PATCH 31/33] proper fix to memleak --- src/zm_event.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index aad16a767..9f1124e7b 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -141,7 +141,6 @@ Event::Event( if (monitor->ServerId()) sql += stringtf(" AND ServerId=%u", monitor->ServerId()); - delete storage; storage = nullptr; MYSQL_RES *result = zmDbFetch(sql); @@ -218,7 +217,8 @@ Event::Event( Debug(1, "Video file is %s", video_file.c_str()); } } // end if GetOptVideoWriter - delete storage; + if (storage != monitor->getStorage()) + delete storage; } Event::~Event() { From 193f349e385f9f41a820c54df993305bc1c5ca75 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 12 Nov 2021 13:36:10 -0500 Subject: [PATCH 32/33] implement Event::canEdit --- web/includes/Event.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/web/includes/Event.php b/web/includes/Event.php index 328b06f66..e042849e9 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -650,6 +650,23 @@ class Event extends ZM_Object { } return false; } + function canEdit($u=null) { + global $user; + if (!$u) $u=$user; + if (!$u) { + # auth turned on and not logged in + return false; + } + if (!empty($u['MonitorIds']) ) { + if (!in_array($this->{'MonitorId'}, explode(',', $u['MonitorIds']))) { + return false; + } + } + if ($u['Events'] != 'Edit') { + return false; + } + return true; + } } # end class ?> From 1561adbef930fc61dbb6885ac42eca7117808872 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 12 Nov 2021 15:11:41 -0500 Subject: [PATCH 33/33] Add title to Download button --- web/skins/classic/views/event.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 81d4e97be..e352f305b 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -150,6 +150,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) ) DefaultVideo() ? '' : 'style="display:none;"' ?> >