From 3d042284857a69496b5404089546458494386b7e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 12 Jan 2022 23:10:17 -0500 Subject: [PATCH] rework ::Analyse. The state engine will only go into alarm on actual motion, not on a skipped frame. TRIGGERS and ONVIF events will immediately create events. --- src/zm_monitor.cpp | 78 ++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 958410efe..587c49f33 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1870,11 +1870,18 @@ bool Monitor::Analyse() { score += 9; Debug(1, "Triggered on ONVIF"); if (!event) { + Event::StringSet noteSet; + noteSet.insert("ONVIF2"); + noteSetMap[MOTION_CAUSE] = noteSet; + + event = openEvent(snap, "ONVIF", noteSetMap); cause += "ONVIF"; + } else { + event->addNote(MOTION_CAUSE, "ONVIF2"); +// Add to cause } - Event::StringSet noteSet; - noteSet.insert("ONVIF2"); - noteSetMap[MOTION_CAUSE] = noteSet; + // Regardless of previous state, we go to ALARM + shared_data->state = state = ALARM; //If the camera isn't going to send an event close, we need to close it here, but only after it has actually triggered an alarm. if (!ONVIF_Closes_Event && state == ALARM) ONVIF_Trigger_State = FALSE; @@ -1886,11 +1893,16 @@ bool Monitor::Analyse() { score += trigger_data->trigger_score; Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score); if (!event) { - cause += trigger_data->trigger_cause; + Event::StringSet noteSet; + noteSet.insert(trigger_data->trigger_text); + noteSetMap[trigger_data->trigger_cause] = noteSet; + event = openEvent(snap, trigger_data->trigger_cause, noteSetMap); + Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name.c_str(), analysis_image_count, event->Id()); + } else { + event->addNote(trigger_data->trigger_cause, trigger_data->trigger_text); + // Need to know if we should end the previous and start a new one, or just add the data } - Event::StringSet noteSet; - noteSet.insert(trigger_data->trigger_text); - noteSetMap[trigger_data->trigger_cause] = noteSet; + shared_data->state = state = ALARM; } // end if trigger_on // FIXME this snap might not be the one that caused the signal change. Need to store that in the packet. @@ -1967,8 +1979,6 @@ bool Monitor::Analyse() { } // end while ! decoded } // end if decoding enabled - SystemTimePoint timestamp = snap->timestamp; - if (Active() and (function == MODECT or function == MOCORD)) { Debug(3, "signal and active and modect"); Event::StringSet zoneSet; @@ -1990,7 +2000,7 @@ bool Monitor::Analyse() { } else if (!(analysis_image_count % (motion_frame_skip+1))) { Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image); // Get new score. - int motion_score = DetectMotion(*(snap->image), zoneSet); + snap->score = DetectMotion(*(snap->image), zoneSet); // lets construct alarm cause. It will contain cause + names of zones alarmed snap->zone_stats.reserve(zones.size()); @@ -2004,11 +2014,11 @@ bool Monitor::Analyse() { } } Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)", - score, last_motion_score, motion_score); + score, last_motion_score, snap->score); motion_frame_count += 1; - last_motion_score = motion_score; + last_motion_score = snap->score; - if (motion_score) { + if (snap->score) { if (cause.length()) cause += ", "; cause += MOTION_CAUSE+std::string(":")+snap->alarm_cause; noteSetMap[MOTION_CAUSE] = zoneSet; @@ -2019,7 +2029,7 @@ bool Monitor::Analyse() { } else { Debug(1, "no image so skipping motion detection"); } // end if has image - score += last_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, @@ -2032,17 +2042,17 @@ bool Monitor::Analyse() { if (event) { Debug(2, "Have event %" PRIu64 " in record", event->Id()); - if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length) + if (section_length != Seconds(0) && (snap->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))) { + || std::chrono::duration_cast(snap->timestamp.time_since_epoch()) % section_length == Seconds(0))) { Info("%s: %03d - Closing event %" PRIu64 ", section end forced %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64 , name.c_str(), image_count, event->Id(), - static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), + static_cast(std::chrono::duration_cast(snap->timestamp.time_since_epoch()).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(std::chrono::duration_cast(snap->timestamp - event->StartTime()).count()), static_cast(Seconds(section_length).count())); closeEvent(); } // end if section_length @@ -2060,13 +2070,14 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function != MONITOR)) { + if ((snap->score > 0) 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() && !event->AlarmFrames() && (event_close_mode == CLOSE_ALARM) - && ((timestamp - event->StartTime()) >= min_section_length) + // FIXME since we won't be including this snap in the event if we close it, we should be looking at event->duration() instead + && ((snap->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()); @@ -2078,7 +2089,7 @@ bool Monitor::Analyse() { Event::PreAlarmCount(), pre_event_count, event->Frames(), event->AlarmFrames(), - static_cast(std::chrono::duration_cast(timestamp - event->StartTime()).count()), + static_cast(std::chrono::duration_cast(snap->timestamp - event->StartTime()).count()), static_cast(Seconds(min_section_length).count()), (event_close_mode == CLOSE_ALARM)); } @@ -2088,12 +2099,10 @@ bool Monitor::Analyse() { if (!event) { event = openEvent(snap, cause, noteSetMap); - shared_data->state = state = ALARM; Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name.c_str(), analysis_image_count, event->Id()); - } else { - shared_data->state = state = ALARM; } // end if no event, so start it - if ( alarm_frame_count ) { + shared_data->state = state = ALARM; + if (alarm_frame_count) { Debug(1, "alarm frame count so SavePreAlarmFrames"); event->SavePreAlarmFrames(); } @@ -2115,13 +2124,13 @@ bool Monitor::Analyse() { Debug(1, "Was in TAPE, going into ALARM"); } else { Debug(1, "Staying in %s", State_Strings[state].c_str()); - } if (state == ALARM) { last_alarm_count = analysis_image_count; } // This is needed so post_event_count counts after last alarmed frames while in ALARM not single alarmed frames while ALERT - } else { // no score? + } else if (!score) { // no snap->score? alert_to_alarm_frame_count = alarm_frame_count; // load same value configured for alarm_frame_count + if (state == ALARM) { Info("%s: %03d - Gone into alert state", name.c_str(), analysis_image_count); shared_data->state = state = ALERT; @@ -2129,7 +2138,7 @@ bool Monitor::Analyse() { if ( ((analysis_image_count - last_alarm_count) > post_event_count) && - ((timestamp - event->StartTime()) >= min_section_length)) { + ((snap->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 ( @@ -2156,7 +2165,7 @@ bool Monitor::Analyse() { analysis_image_count, last_alarm_count, post_event_count, - static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), + static_cast(std::chrono::duration_cast(snap->timestamp.time_since_epoch()).count()), static_cast(std::chrono::duration_cast(GetVideoWriterStartTime().time_since_epoch()).count()), static_cast(Seconds(min_section_length).count())); } @@ -2164,7 +2173,8 @@ bool Monitor::Analyse() { Event::EmptyPreAlarmFrames(); } // end if score or not - snap->score = score; + if (score > snap->score) + snap->score = score; if (state == PREALARM) { // Generate analysis images if necessary @@ -2181,7 +2191,7 @@ bool Monitor::Analyse() { } // end if image. // incremement pre alarm image count - Event::AddPreAlarmFrame(snap->image, timestamp, score, nullptr); + Event::AddPreAlarmFrame(snap->image, snap->timestamp, score, nullptr); } else if (state == ALARM) { if (snap->image) { for (const Zone &zone : zones) { @@ -2198,12 +2208,12 @@ bool Monitor::Analyse() { if (event) { if (noteSetMap.size() > 0) event->updateNotes(noteSetMap); - if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length)) { + if (section_length != Seconds(0) && (snap->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()), + static_cast(std::chrono::duration_cast(snap->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(snap->timestamp - GetVideoWriterStartTime()).count()), static_cast(Seconds(section_length).count())); closeEvent(); event = openEvent(snap, cause, noteSetMap);