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.

This commit is contained in:
Isaac Connor 2022-01-12 23:10:17 -05:00
parent e4693c251c
commit 3d04228485
1 changed files with 44 additions and 34 deletions

View File

@ -1870,11 +1870,18 @@ bool Monitor::Analyse() {
score += 9; score += 9;
Debug(1, "Triggered on ONVIF"); Debug(1, "Triggered on ONVIF");
if (!event) { if (!event) {
Event::StringSet noteSet;
noteSet.insert("ONVIF2");
noteSetMap[MOTION_CAUSE] = noteSet;
event = openEvent(snap, "ONVIF", noteSetMap);
cause += "ONVIF"; cause += "ONVIF";
} else {
event->addNote(MOTION_CAUSE, "ONVIF2");
// Add to cause
} }
Event::StringSet noteSet; // Regardless of previous state, we go to ALARM
noteSet.insert("ONVIF2"); shared_data->state = state = ALARM;
noteSetMap[MOTION_CAUSE] = noteSet;
//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 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) if (!ONVIF_Closes_Event && state == ALARM)
ONVIF_Trigger_State = FALSE; ONVIF_Trigger_State = FALSE;
@ -1886,11 +1893,16 @@ bool Monitor::Analyse() {
score += trigger_data->trigger_score; score += trigger_data->trigger_score;
Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score); Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score);
if (!event) { 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; shared_data->state = state = ALARM;
noteSet.insert(trigger_data->trigger_text);
noteSetMap[trigger_data->trigger_cause] = noteSet;
} // end if trigger_on } // end if trigger_on
// FIXME this snap might not be the one that caused the signal change. Need to store that in the packet. // 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 while ! decoded
} // end if decoding enabled } // end if decoding enabled
SystemTimePoint timestamp = snap->timestamp;
if (Active() and (function == MODECT or function == MOCORD)) { if (Active() and (function == MODECT or function == MOCORD)) {
Debug(3, "signal and active and modect"); Debug(3, "signal and active and modect");
Event::StringSet zoneSet; Event::StringSet zoneSet;
@ -1990,7 +2000,7 @@ bool Monitor::Analyse() {
} else if (!(analysis_image_count % (motion_frame_skip+1))) { } else if (!(analysis_image_count % (motion_frame_skip+1))) {
Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image); Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image);
// Get new score. // 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 // lets construct alarm cause. It will contain cause + names of zones alarmed
snap->zone_stats.reserve(zones.size()); 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)", 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; motion_frame_count += 1;
last_motion_score = motion_score; last_motion_score = snap->score;
if (motion_score) { if (snap->score) {
if (cause.length()) cause += ", "; if (cause.length()) cause += ", ";
cause += MOTION_CAUSE+std::string(":")+snap->alarm_cause; cause += MOTION_CAUSE+std::string(":")+snap->alarm_cause;
noteSetMap[MOTION_CAUSE] = zoneSet; noteSetMap[MOTION_CAUSE] = zoneSet;
@ -2019,7 +2029,7 @@ bool Monitor::Analyse() {
} else { } else {
Debug(1, "no image so skipping motion detection"); Debug(1, "no image so skipping motion detection");
} // end if has image } // end if has image
score += last_motion_score; //score += last_motion_score;
} else { } else {
Debug(1, "Not Active(%d) enabled %d active %d doing motion detection: %d", Debug(1, "Not Active(%d) enabled %d active %d doing motion detection: %d",
Active(), enabled, shared_data->active, Active(), enabled, shared_data->active,
@ -2032,17 +2042,17 @@ bool Monitor::Analyse() {
if (event) { if (event) {
Debug(2, "Have event %" PRIu64 " in record", event->Id()); 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 == MOCORD && event_close_mode != CLOSE_TIME)
|| (function == RECORD && event_close_mode == CLOSE_TIME) || (function == RECORD && event_close_mode == CLOSE_TIME)
|| std::chrono::duration_cast<Seconds>(timestamp.time_since_epoch()) % section_length == Seconds(0))) { || std::chrono::duration_cast<Seconds>(snap->timestamp.time_since_epoch()) % section_length == Seconds(0))) {
Info("%s: %03d - Closing event %" PRIu64 ", section end forced %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64 , Info("%s: %03d - Closing event %" PRIu64 ", section end forced %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64 ,
name.c_str(), name.c_str(),
image_count, image_count,
event->Id(), event->Id(),
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp.time_since_epoch()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(snap->timestamp.time_since_epoch()).count()),
static_cast<int64>(std::chrono::duration_cast<Seconds>(event->StartTime().time_since_epoch()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(event->StartTime().time_since_epoch()).count()),
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - event->StartTime()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(snap->timestamp - event->StartTime()).count()),
static_cast<int64>(Seconds(section_length).count())); static_cast<int64>(Seconds(section_length).count()));
closeEvent(); closeEvent();
} // end if section_length } // end if section_length
@ -2060,13 +2070,14 @@ bool Monitor::Analyse() {
} // end if ! event } // end if ! event
} // end if RECORDING } // end if RECORDING
if (score and (function != MONITOR)) { if ((snap->score > 0) and (function != MONITOR)) {
if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) { if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) {
// If we should end then previous continuous event and start a new non-continuous event // If we should end then previous continuous event and start a new non-continuous event
if (event && event->Frames() if (event && event->Frames()
&& !event->AlarmFrames() && !event->AlarmFrames()
&& (event_close_mode == CLOSE_ALARM) && (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))) { && ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count - 1))) {
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins", Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
name.c_str(), image_count, event->Id()); name.c_str(), image_count, event->Id());
@ -2078,7 +2089,7 @@ bool Monitor::Analyse() {
Event::PreAlarmCount(), pre_event_count, Event::PreAlarmCount(), pre_event_count,
event->Frames(), event->Frames(),
event->AlarmFrames(), event->AlarmFrames(),
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - event->StartTime()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(snap->timestamp - event->StartTime()).count()),
static_cast<int64>(Seconds(min_section_length).count()), static_cast<int64>(Seconds(min_section_length).count()),
(event_close_mode == CLOSE_ALARM)); (event_close_mode == CLOSE_ALARM));
} }
@ -2088,12 +2099,10 @@ bool Monitor::Analyse() {
if (!event) { if (!event) {
event = openEvent(snap, cause, noteSetMap); 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()); 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 } // 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"); Debug(1, "alarm frame count so SavePreAlarmFrames");
event->SavePreAlarmFrames(); event->SavePreAlarmFrames();
} }
@ -2115,13 +2124,13 @@ bool Monitor::Analyse() {
Debug(1, "Was in TAPE, going into ALARM"); Debug(1, "Was in TAPE, going into ALARM");
} else { } else {
Debug(1, "Staying in %s", State_Strings[state].c_str()); Debug(1, "Staying in %s", State_Strings[state].c_str());
} }
if (state == ALARM) { if (state == ALARM) {
last_alarm_count = analysis_image_count; 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 } // 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 alert_to_alarm_frame_count = alarm_frame_count; // load same value configured for alarm_frame_count
if (state == ALARM) { if (state == ALARM) {
Info("%s: %03d - Gone into alert state", name.c_str(), analysis_image_count); Info("%s: %03d - Gone into alert state", name.c_str(), analysis_image_count);
shared_data->state = state = ALERT; shared_data->state = state = ALERT;
@ -2129,7 +2138,7 @@ bool Monitor::Analyse() {
if ( if (
((analysis_image_count - last_alarm_count) > post_event_count) ((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", Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images",
name.c_str(), analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames()); name.c_str(), analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames());
if ( if (
@ -2156,7 +2165,7 @@ bool Monitor::Analyse() {
analysis_image_count, analysis_image_count,
last_alarm_count, last_alarm_count,
post_event_count, post_event_count,
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp.time_since_epoch()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(snap->timestamp.time_since_epoch()).count()),
static_cast<int64>(std::chrono::duration_cast<Seconds>(GetVideoWriterStartTime().time_since_epoch()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(GetVideoWriterStartTime().time_since_epoch()).count()),
static_cast<int64>(Seconds(min_section_length).count())); static_cast<int64>(Seconds(min_section_length).count()));
} }
@ -2164,7 +2173,8 @@ bool Monitor::Analyse() {
Event::EmptyPreAlarmFrames(); Event::EmptyPreAlarmFrames();
} // end if score or not } // end if score or not
snap->score = score; if (score > snap->score)
snap->score = score;
if (state == PREALARM) { if (state == PREALARM) {
// Generate analysis images if necessary // Generate analysis images if necessary
@ -2181,7 +2191,7 @@ bool Monitor::Analyse() {
} // end if image. } // end if image.
// incremement pre alarm image count // incremement pre alarm image count
Event::AddPreAlarmFrame(snap->image, timestamp, score, nullptr); Event::AddPreAlarmFrame(snap->image, snap->timestamp, score, nullptr);
} else if (state == ALARM) { } else if (state == ALARM) {
if (snap->image) { if (snap->image) {
for (const Zone &zone : zones) { for (const Zone &zone : zones) {
@ -2198,12 +2208,12 @@ bool Monitor::Analyse() {
if (event) { if (event) {
if (noteSetMap.size() > 0) if (noteSetMap.size() > 0)
event->updateNotes(noteSetMap); 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, Warning("%s: %03d - event %" PRIu64 ", has exceeded desired section length. %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64,
name.c_str(), analysis_image_count, event->Id(), name.c_str(), analysis_image_count, event->Id(),
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp.time_since_epoch()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(snap->timestamp.time_since_epoch()).count()),
static_cast<int64>(std::chrono::duration_cast<Seconds>(GetVideoWriterStartTime().time_since_epoch()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(GetVideoWriterStartTime().time_since_epoch()).count()),
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(snap->timestamp - GetVideoWriterStartTime()).count()),
static_cast<int64>(Seconds(section_length).count())); static_cast<int64>(Seconds(section_length).count()));
closeEvent(); closeEvent();
event = openEvent(snap, cause, noteSetMap); event = openEvent(snap, cause, noteSetMap);