Merge branch 'master' of github.com:ZoneMinder/zoneminder
This commit is contained in:
commit
96a58f8c88
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<Microseconds>(event_data->end_time - event_data->start_time);
|
||||
event_data->frames_duration =
|
||||
std::chrono::duration_cast<Microseconds>(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0));
|
||||
|
|
|
@ -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 != 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()
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 '
|
||||
<tr>
|
||||
<th scope="row">'.translate($setting_uc).'</th>
|
||||
<th scope="row">'.$label.'</th>
|
||||
<td>'.$min.'</td><td><input type="range" title="'.$value.'" min="'.$min.'" max="'.$max.'" step="'.$step.'" default="'.$default.'" value="'.$value.'" id="new'.$setting_uc.'" name="new'.$setting_uc.'" '.(canEdit('Control') ? '' : 'disabled="disabled"') .'/></td><td>'.$max.'</td>
|
||||
</tr>
|
||||
';
|
||||
|
@ -94,7 +99,7 @@ foreach ($ctls as $line) {
|
|||
if ($type == '(bool)') {
|
||||
echo '
|
||||
<tr>
|
||||
<th scope="row">'.translate($setting_uc).'</th>
|
||||
<th scope="row">'.$label.'</th>
|
||||
<td></td><td>'.html_radio('new'.$setting_uc, array('0'=>translate('True'), '1', translate('False')), $value, array('disabled'=>'disabled')).'
|
||||
</td><td></td>
|
||||
</tr>
|
||||
|
@ -102,14 +107,14 @@ foreach ($ctls as $line) {
|
|||
} else if ($type == '(int)') {
|
||||
echo '
|
||||
<tr>
|
||||
<th scope="row">'.translate($setting_uc).'</th>
|
||||
<th scope="row">'.$label.'</th>
|
||||
<td></td><td><input type="range" '.$ctl[1].' disabled="disabled"/></td><td></td>
|
||||
</tr>
|
||||
';
|
||||
} else {
|
||||
echo '
|
||||
<tr>
|
||||
<th scope="row">'.translate($setting_uc).'</th>
|
||||
<th scope="row">'.$label.'</th>
|
||||
<td></td><td>'.$value.'</td><td></td>
|
||||
</tr>
|
||||
';
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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});
|
||||
|
|
|
@ -461,9 +461,12 @@ switch ( $name ) {
|
|||
<tr class="Id">
|
||||
<td class="text-right pr-3"><?php echo translate('Id') ?></td>
|
||||
<td><input type="number" step="1" min="1" name="newMonitor[Id]" placeholder="leave blank for auto"/><br/>
|
||||
10 Available Ids:
|
||||
<?php echo implode(', ', array_slice($available_monitor_ids, 0, 10)); ?>
|
||||
</td>
|
||||
<?php
|
||||
if (count($available_monitor_ids)) {
|
||||
echo 'Some available ids: '.implode(', ', array_slice($available_monitor_ids, 0, 10));
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
|
|
Loading…
Reference in New Issue