From 97877335db4a11b3a124f5b38f0d71e48a3f250d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Jul 2025 16:17:36 -0400 Subject: [PATCH] Add MaxScoreFrameId to the events table and automatically update it during event creation so we don't have to look it up later. Finding the frame with the max score is actually a very heavy query, so lets not do it. --- db/zm_create.sql.in | 1 + db/zm_update-1.37.68.sql | 17 +++++++++++++++++ distros/redhat/zoneminder.spec | 2 +- src/zm_event.cpp | 13 ++++++++----- src/zm_event.h | 1 + version.txt | 2 +- web/api/app/Controller/EventsController.php | 5 +++-- 7 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 db/zm_update-1.37.68.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 452142e56..b1023e5ef 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -203,6 +203,7 @@ CREATE TABLE `Events` ( `TotScore` int(10) unsigned NOT NULL default '0', `AvgScore` smallint(5) unsigned default '0', `MaxScore` smallint(5) unsigned default '0', + `MaxScoreFrameId` int(10) unsigned default NULL, `Archived` tinyint(3) unsigned NOT NULL default '0', `Videoed` tinyint(3) unsigned NOT NULL default '0', `Uploaded` tinyint(3) unsigned NOT NULL default '0', diff --git a/db/zm_update-1.37.68.sql b/db/zm_update-1.37.68.sql new file mode 100644 index 000000000..6868838a7 --- /dev/null +++ b/db/zm_update-1.37.68.sql @@ -0,0 +1,17 @@ +-- +-- Update Events table to have MaxScoreFrameId +-- + +SELECT 'Checking for MaxScoreFrameId in Events'; +SET @s = (SELECT IF( + (SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'Events' + AND table_schema = DATABASE() + AND column_name = 'MaxScoreFrameId' + ) > 0, +"SELECT 'Column MaxScoreFrameId already exists in Events'", + "ALTER TABLE `Events` ADD COLUMN `MaxScoreFrameId` int(10) unsigned default NULL AFTER `MaxScore`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index b56cd14af..2a236fd95 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -18,7 +18,7 @@ %global zmtargetdistro %{?rhel:el%{rhel}}%{!?rhel:fc%{fedora}} Name: zoneminder -Version: 1.37.67 +Version: 1.37.68 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 58882655e..f7bffc9cc 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -62,6 +62,7 @@ Event::Event( alarm_frame_written(false), tot_score(0), max_score(-1), + max_score_frame_id(0), //path(""), //snapshit_file(), snapshot_file_written(false), @@ -200,11 +201,11 @@ Event::~Event() { } std::string sql = stringtf( - "UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s', DiskSpace=%" PRIu64 " WHERE Id = %" PRIu64 " AND Name='New Event'", + "UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, MaxScoreFrameId=%d, DefaultVideo='%s', DiskSpace=%" PRIu64 " WHERE Id = %" PRIu64 " AND Name='New Event'", monitor->Substitute(monitor->EventPrefix(), start_time).c_str(), id, std::chrono::system_clock::to_time_t(end_time), delta_time.count(), frames, alarm_frames, - tot_score, static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, + tot_score, static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, max_score_frame_id, video_file.c_str(), // defaults to "" video_size, id); @@ -212,11 +213,11 @@ Event::~Event() { if (!zmDbDoUpdate(sql)) { // Name might have been changed during recording, so just do the update without changing the name. sql = stringtf( - "UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s', DiskSpace=%" PRIu64 " WHERE Id = %" PRIu64, + "UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, MaxScoreFrameId=%d, DefaultVideo='%s', DiskSpace=%" PRIu64 " WHERE Id = %" PRIu64, std::chrono::system_clock::to_time_t(end_time), delta_time.count(), frames, alarm_frames, - tot_score, static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, + tot_score, static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, max_score_frame_id, video_file.c_str(), // defaults to "" video_size, id); @@ -516,6 +517,7 @@ void Event::AddFrame(const std::shared_ptr&packet) { if (score > max_score) { max_score = score; + max_score_frame_id = frames; } if (db_frame) { @@ -543,13 +545,14 @@ void Event::AddFrame(const std::shared_ptr&packet) { last_db_frame = frames; std::string sql = stringtf( - "UPDATE Events SET Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, + "UPDATE Events SET Length=%.2f, Frames=%d, AlarmFrames=%d, TotScore=%d, AvgScore=%d, MaxScore=%d, MaxScoreFrameId=%d WHERE Id=%" PRIu64, FPSeconds(delta_time).count(), frames, alarm_frames, tot_score, static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, + max_score_frame_id, id); dbQueue.push(std::move(sql)); } else { diff --git a/src/zm_event.h b/src/zm_event.h index 2ae743640..aa467c02b 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -90,6 +90,7 @@ class Event { bool alarm_frame_written; int tot_score; int max_score; + int max_score_frame_id; std::string path; std::string snapshot_file; bool snapshot_file_written; diff --git a/version.txt b/version.txt index 059c09436..abd7cc2f7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.37.67 +1.37.68 diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 8923ddc69..0c15098d6 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -108,8 +108,9 @@ class EventsController extends AppController { foreach ( $events as $key => $value ) { $EventObj = new ZM\Event($value['Event']); - $maxScoreFrameId = $this->getMaxScoreAlarmFrameId($value['Event']['Id']); - $events[$key]['Event']['MaxScoreFrameId'] = $maxScoreFrameId; + if ($EventObj['MaxScoreFrameId'] == NULL) { + $EventObj['MaxScoreFrameId'] = $this->getMaxScoreAlarmFrameId($value['Event']['Id']); + } $events[$key]['Event']['FileSystemPath'] = $EventObj->Path(); }