Merge branch 'master' of github.com:ZoneMinder/zoneminder
This commit is contained in:
commit
6d30f5431b
|
@ -4,7 +4,7 @@
|
||||||
web/api/lib
|
web/api/lib
|
||||||
web/includes/csrf/
|
web/includes/csrf/
|
||||||
web/js/videojs.zoomrotate.js
|
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/chosen
|
||||||
web/skins/classic/js/dateTimePicker
|
web/skins/classic/js/dateTimePicker
|
||||||
web/skins/classic/js/jquery-*.js
|
web/skins/classic/js/jquery-*.js
|
||||||
|
|
|
@ -255,7 +255,7 @@ void zmDbQueue::process() {
|
||||||
Logger *log = Logger::fetch();
|
Logger *log = Logger::fetch();
|
||||||
Logger::Level db_level = log->databaseLevel();
|
Logger::Level db_level = log->databaseLevel();
|
||||||
log->databaseLevel(Logger::NOLOG);
|
log->databaseLevel(Logger::NOLOG);
|
||||||
Warning("db queue size has grown larger than 10 entries");
|
Warning("db queue size has grown larger %zu than 10 entries", mQueue.size());
|
||||||
log->databaseLevel(db_level);
|
log->databaseLevel(db_level);
|
||||||
}
|
}
|
||||||
std::string sql = mQueue.front();
|
std::string sql = mQueue.front();
|
||||||
|
|
100
src/zm_event.cpp
100
src/zm_event.cpp
|
@ -60,8 +60,8 @@ Event::Event(
|
||||||
//snapshit_file(),
|
//snapshit_file(),
|
||||||
//alarm_file(""),
|
//alarm_file(""),
|
||||||
videoStore(nullptr),
|
videoStore(nullptr),
|
||||||
//video_name(""),
|
|
||||||
//video_file(""),
|
//video_file(""),
|
||||||
|
//video_path(""),
|
||||||
last_db_frame(0),
|
last_db_frame(0),
|
||||||
have_video_keyframe(false),
|
have_video_keyframe(false),
|
||||||
//scheme
|
//scheme
|
||||||
|
@ -103,7 +103,14 @@ Event::Event(
|
||||||
|
|
||||||
// Copy it in case opening the mp4 doesn't work we can set it to another value
|
// Copy it in case opening the mp4 doesn't work we can set it to another value
|
||||||
save_jpegs = monitor->GetOptSaveJPEGs();
|
save_jpegs = monitor->GetOptSaveJPEGs();
|
||||||
Storage * storage = monitor->getStorage();
|
Storage *storage = monitor->getStorage();
|
||||||
|
if (monitor->GetOptVideoWriter() != 0) {
|
||||||
|
container = monitor->OutputContainer();
|
||||||
|
if ( container == "auto" || container == "" ) {
|
||||||
|
container = "mp4";
|
||||||
|
}
|
||||||
|
video_incomplete_file = "incomplete."+container;
|
||||||
|
}
|
||||||
|
|
||||||
std::string sql = stringtf(
|
std::string sql = stringtf(
|
||||||
"INSERT INTO `Events` "
|
"INSERT INTO `Events` "
|
||||||
|
@ -120,28 +127,28 @@ Event::Event(
|
||||||
state_id,
|
state_id,
|
||||||
monitor->getOrientation(),
|
monitor->getOrientation(),
|
||||||
0,
|
0,
|
||||||
"",
|
video_incomplete_file.c_str(),
|
||||||
save_jpegs,
|
save_jpegs,
|
||||||
storage->SchemeString().c_str()
|
storage->SchemeString().c_str()
|
||||||
);
|
);
|
||||||
id = zmDbDoInsert(sql);
|
id = zmDbDoInsert(sql);
|
||||||
|
|
||||||
if ( !SetPath(storage) ) {
|
if (!SetPath(storage)) {
|
||||||
// Try another
|
// Try another
|
||||||
Warning("Failed creating event dir at %s", storage->Path());
|
Warning("Failed creating event dir at %s", storage->Path());
|
||||||
|
|
||||||
sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id());
|
sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id());
|
||||||
if ( monitor->ServerId() )
|
if (monitor->ServerId())
|
||||||
sql += stringtf(" AND ServerId=%u", monitor->ServerId());
|
sql += stringtf(" AND ServerId=%u", monitor->ServerId());
|
||||||
|
|
||||||
Debug(1, "%s", sql.c_str());
|
delete storage;
|
||||||
storage = nullptr;
|
storage = nullptr;
|
||||||
|
|
||||||
MYSQL_RES *result = zmDbFetch(sql);
|
MYSQL_RES *result = zmDbFetch(sql);
|
||||||
if ( result ) {
|
if (result) {
|
||||||
for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
for (int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) {
|
||||||
storage = new Storage(atoi(dbrow[0]));
|
storage = new Storage(atoi(dbrow[0]));
|
||||||
if ( SetPath(storage) )
|
if (SetPath(storage))
|
||||||
break;
|
break;
|
||||||
delete storage;
|
delete storage;
|
||||||
storage = nullptr;
|
storage = nullptr;
|
||||||
|
@ -149,18 +156,18 @@ Event::Event(
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
result = nullptr;
|
result = nullptr;
|
||||||
}
|
}
|
||||||
if ( !storage ) {
|
if (!storage) {
|
||||||
Info("No valid local storage area found. Trying all other areas.");
|
Info("No valid local storage area found. Trying all other areas.");
|
||||||
// Try remote
|
// Try remote
|
||||||
sql = "SELECT `Id` FROM `Storage` WHERE ServerId IS NULL";
|
sql = "SELECT `Id` FROM `Storage` WHERE ServerId IS NULL";
|
||||||
if ( monitor->ServerId() )
|
if (monitor->ServerId())
|
||||||
sql += stringtf(" OR ServerId != %u", monitor->ServerId());
|
sql += stringtf(" OR ServerId != %u", monitor->ServerId());
|
||||||
|
|
||||||
result = zmDbFetch(sql);
|
result = zmDbFetch(sql);
|
||||||
if ( result ) {
|
if (result) {
|
||||||
for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
||||||
storage = new Storage(atoi(dbrow[0]));
|
storage = new Storage(atoi(dbrow[0]));
|
||||||
if ( SetPath(storage) )
|
if (SetPath(storage))
|
||||||
break;
|
break;
|
||||||
delete storage;
|
delete storage;
|
||||||
storage = nullptr;
|
storage = nullptr;
|
||||||
|
@ -169,7 +176,7 @@ Event::Event(
|
||||||
result = nullptr;
|
result = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !storage ) {
|
if (!storage) {
|
||||||
storage = new Storage();
|
storage = new Storage();
|
||||||
Warning("Failed to find a storage area to save events.");
|
Warning("Failed to find a storage area to save events.");
|
||||||
}
|
}
|
||||||
|
@ -178,24 +185,16 @@ Event::Event(
|
||||||
} // end if ! setPath(Storage)
|
} // end if ! setPath(Storage)
|
||||||
Debug(1, "Using storage area at %s", path.c_str());
|
Debug(1, "Using storage area at %s", path.c_str());
|
||||||
|
|
||||||
video_name = "";
|
|
||||||
|
|
||||||
snapshot_file = path + "/snapshot.jpg";
|
snapshot_file = path + "/snapshot.jpg";
|
||||||
alarm_file = path + "/alarm.jpg";
|
alarm_file = path + "/alarm.jpg";
|
||||||
|
|
||||||
|
video_incomplete_path = path + "/" + video_incomplete_file;
|
||||||
|
|
||||||
|
if (monitor->GetOptVideoWriter() != 0) {
|
||||||
/* Save as video */
|
/* Save as video */
|
||||||
|
|
||||||
if ( monitor->GetOptVideoWriter() != 0 ) {
|
|
||||||
std::string container = monitor->OutputContainer();
|
|
||||||
if ( container == "auto" || container == "" ) {
|
|
||||||
container = "mp4";
|
|
||||||
}
|
|
||||||
|
|
||||||
video_name = stringtf("%" PRIu64 "-%s.%s", id, "video", container.c_str());
|
|
||||||
video_file = path + "/" + video_name;
|
|
||||||
Debug(1, "Writing video file to %s", video_file.c_str());
|
|
||||||
videoStore = new VideoStore(
|
videoStore = new VideoStore(
|
||||||
video_file.c_str(),
|
video_incomplete_path.c_str(),
|
||||||
container.c_str(),
|
container.c_str(),
|
||||||
monitor->GetVideoStream(),
|
monitor->GetVideoStream(),
|
||||||
monitor->GetVideoCodecContext(),
|
monitor->GetVideoCodecContext(),
|
||||||
|
@ -213,20 +212,31 @@ Event::Event(
|
||||||
zmDbDo(sql);
|
zmDbDo(sql);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sql = stringtf("UPDATE Events SET Videoed=1, DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
|
std::string codec = videoStore->get_codec();
|
||||||
zmDbDo(sql);
|
video_file = stringtf("%" PRIu64 "-%s.%s.%s", id, "video", codec.c_str(), container.c_str());
|
||||||
|
video_path = path + "/" + video_file;
|
||||||
|
Debug(1, "Video file is %s", video_file.c_str());
|
||||||
}
|
}
|
||||||
} // end if GetOptVideoWriter
|
} // end if GetOptVideoWriter
|
||||||
|
delete storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::~Event() {
|
Event::~Event() {
|
||||||
// We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet.
|
// We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet.
|
||||||
|
|
||||||
/* Close the video file */
|
/* Close the video file */
|
||||||
if ( videoStore != nullptr ) {
|
if (videoStore != nullptr) {
|
||||||
Debug(4, "Deleting video store");
|
Debug(4, "Deleting video store");
|
||||||
delete videoStore;
|
delete videoStore;
|
||||||
videoStore = nullptr;
|
videoStore = nullptr;
|
||||||
|
int result = rename(video_incomplete_path.c_str(), video_path.c_str());
|
||||||
|
if (result == 0) {
|
||||||
|
Debug(1, "File successfully renamed");
|
||||||
|
} else {
|
||||||
|
Error("Failed renaming %s to %s", video_incomplete_path.c_str(), video_path.c_str());
|
||||||
|
// So that we don't update the event record
|
||||||
|
video_file = video_incomplete_file;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// endtime is set in AddFrame, so SHOULD be set to the value of the last frame timestamp.
|
// endtime is set in AddFrame, so SHOULD be set to the value of the last frame timestamp.
|
||||||
|
@ -245,21 +255,23 @@ Event::~Event() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sql = stringtf(
|
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 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, DefaultVideo='%s' WHERE Id = %" PRIu64 " AND Name='New Event'",
|
||||||
monitor->EventPrefix(), id, std::chrono::system_clock::to_time_t(end_time),
|
monitor->EventPrefix(), id, std::chrono::system_clock::to_time_t(end_time),
|
||||||
delta_time.count(),
|
delta_time.count(),
|
||||||
frames, alarm_frames,
|
frames, alarm_frames,
|
||||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||||
|
video_file.c_str(), // defaults to ""
|
||||||
id);
|
id);
|
||||||
|
|
||||||
if (!zmDbDoUpdate(sql)) {
|
if (!zmDbDoUpdate(sql)) {
|
||||||
// Name might have been changed during recording, so just do the update without changing the name.
|
// Name might have been changed during recording, so just do the update without changing the name.
|
||||||
sql = stringtf(
|
sql = stringtf(
|
||||||
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
|
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64,
|
||||||
std::chrono::system_clock::to_time_t(end_time),
|
std::chrono::system_clock::to_time_t(end_time),
|
||||||
delta_time.count(),
|
delta_time.count(),
|
||||||
frames, alarm_frames,
|
frames, alarm_frames,
|
||||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||||
|
video_file.c_str(), // defaults to ""
|
||||||
id);
|
id);
|
||||||
zmDbDoUpdate(sql);
|
zmDbDoUpdate(sql);
|
||||||
} // end if no changed rows due to Name change during recording
|
} // end if no changed rows due to Name change during recording
|
||||||
|
@ -312,32 +324,32 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) {
|
||||||
bool update = false;
|
bool update = false;
|
||||||
|
|
||||||
//Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() );
|
//Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() );
|
||||||
if ( newNoteSetMap.size() > 0 ) {
|
if (newNoteSetMap.size() > 0) {
|
||||||
if ( noteSetMap.size() == 0 ) {
|
if (noteSetMap.size() == 0) {
|
||||||
noteSetMap = newNoteSetMap;
|
noteSetMap = newNoteSetMap;
|
||||||
update = true;
|
update = true;
|
||||||
} else {
|
} else {
|
||||||
for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin();
|
for (StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin();
|
||||||
newNoteSetMapIter != newNoteSetMap.end();
|
newNoteSetMapIter != newNoteSetMap.end();
|
||||||
++newNoteSetMapIter ) {
|
++newNoteSetMapIter) {
|
||||||
const std::string &newNoteGroup = newNoteSetMapIter->first;
|
const std::string &newNoteGroup = newNoteSetMapIter->first;
|
||||||
const StringSet &newNoteSet = newNoteSetMapIter->second;
|
const StringSet &newNoteSet = newNoteSetMapIter->second;
|
||||||
//Info( "Got %d new strings", newNoteSet.size() );
|
//Info( "Got %d new strings", newNoteSet.size() );
|
||||||
if ( newNoteSet.size() > 0 ) {
|
if (newNoteSet.size() > 0) {
|
||||||
StringSetMap::iterator noteSetMapIter = noteSetMap.find(newNoteGroup);
|
StringSetMap::iterator noteSetMapIter = noteSetMap.find(newNoteGroup);
|
||||||
if ( noteSetMapIter == noteSetMap.end() ) {
|
if (noteSetMapIter == noteSetMap.end()) {
|
||||||
//Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() );
|
//Debug(3, "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size());
|
||||||
noteSetMap.insert(StringSetMap::value_type(newNoteGroup, newNoteSet));
|
noteSetMap.insert(StringSetMap::value_type(newNoteGroup, newNoteSet));
|
||||||
update = true;
|
update = true;
|
||||||
} else {
|
} else {
|
||||||
StringSet ¬eSet = noteSetMapIter->second;
|
StringSet ¬eSet = noteSetMapIter->second;
|
||||||
//Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() );
|
//Debug(3, "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size());
|
||||||
for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin();
|
for (StringSet::const_iterator newNoteSetIter = newNoteSet.begin();
|
||||||
newNoteSetIter != newNoteSet.end();
|
newNoteSetIter != newNoteSet.end();
|
||||||
++newNoteSetIter ) {
|
++newNoteSetIter) {
|
||||||
const std::string &newNote = *newNoteSetIter;
|
const std::string &newNote = *newNoteSetIter;
|
||||||
StringSet::iterator noteSetIter = noteSet.find(newNote);
|
StringSet::iterator noteSetIter = noteSet.find(newNote);
|
||||||
if ( noteSetIter == noteSet.end() ) {
|
if (noteSetIter == noteSet.end()) {
|
||||||
noteSet.insert(newNote);
|
noteSet.insert(newNote);
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
|
@ -479,7 +491,7 @@ void Event::AddFrame(Image *image,
|
||||||
Debug(1, "Writing snapshot");
|
Debug(1, "Writing snapshot");
|
||||||
WriteFrameImage(image, timestamp, snapshot_file.c_str());
|
WriteFrameImage(image, timestamp, snapshot_file.c_str());
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "Not Writing snapshot");
|
Debug(1, "Not Writing snapshot because score %d > max %d", score, max_score);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are writing an Alarm frame
|
// We are writing an Alarm frame
|
||||||
|
@ -491,7 +503,7 @@ void Event::AddFrame(Image *image,
|
||||||
Debug(1, "Writing alarm image");
|
Debug(1, "Writing alarm image");
|
||||||
WriteFrameImage(image, timestamp, alarm_file.c_str());
|
WriteFrameImage(image, timestamp, alarm_file.c_str());
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "Not Writing alarm image");
|
Debug(3, "Not Writing alarm image because alarm frame already written");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alarm_image and (save_jpegs & 2)) {
|
if (alarm_image and (save_jpegs & 2)) {
|
||||||
|
|
|
@ -84,8 +84,13 @@ class Event {
|
||||||
std::string alarm_file;
|
std::string alarm_file;
|
||||||
VideoStore *videoStore;
|
VideoStore *videoStore;
|
||||||
|
|
||||||
std::string video_name;
|
std::string container;
|
||||||
|
std::string codec;
|
||||||
std::string video_file;
|
std::string video_file;
|
||||||
|
std::string video_path;
|
||||||
|
std::string video_incomplete_file;
|
||||||
|
std::string video_incomplete_path;
|
||||||
|
|
||||||
int last_db_frame;
|
int last_db_frame;
|
||||||
bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe.
|
bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe.
|
||||||
Storage::Schemes scheme;
|
Storage::Schemes scheme;
|
||||||
|
|
|
@ -141,7 +141,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0;
|
event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0;
|
||||||
event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]);
|
event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]);
|
||||||
event_data->start_time = SystemTimePoint(Seconds(atoi(dbrow[3])));
|
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->duration = std::chrono::duration_cast<Microseconds>(event_data->end_time - event_data->start_time);
|
||||||
event_data->frames_duration =
|
event_data->frames_duration =
|
||||||
std::chrono::duration_cast<Microseconds>(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0));
|
std::chrono::duration_cast<Microseconds>(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0));
|
||||||
|
|
|
@ -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) {
|
bool Fifo::write(uint8_t *data, size_t bytes, int64_t pts) {
|
||||||
if (!(outfile or open())) return false;
|
if (!(outfile or open())) return false;
|
||||||
// Going to write a brief header
|
// Going to write a brief header
|
||||||
Debug(1, "Writing header ZM %lu %" PRId64, bytes, pts);
|
Debug(1, "Writing header ZM %zu %" PRId64, bytes, pts);
|
||||||
if ( fprintf(outfile, "ZM %lu %" PRId64 "\n", bytes, pts) < 0 ) {
|
if (fprintf(outfile, "ZM %zu %" PRId64 "\n", bytes, pts) < 0) {
|
||||||
if (errno != EAGAIN) {
|
if (errno != EAGAIN) {
|
||||||
Error("Problem during writing: %s", strerror(errno));
|
Error("Problem during writing: %s", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -270,7 +270,6 @@ int Image::PopulateFrame(AVFrame *frame) {
|
||||||
frame->width = width;
|
frame->width = width;
|
||||||
frame->height = height;
|
frame->height = height;
|
||||||
frame->format = imagePixFormat;
|
frame->format = imagePixFormat;
|
||||||
Debug(1, "PopulateFrame: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, size);
|
|
||||||
zm_dump_video_frame(frame, "Image.Populate(frame)");
|
zm_dump_video_frame(frame, "Image.Populate(frame)");
|
||||||
return 1;
|
return 1;
|
||||||
} // int Image::PopulateFrame(AVFrame *frame)
|
} // int Image::PopulateFrame(AVFrame *frame)
|
||||||
|
|
|
@ -155,7 +155,7 @@ bool Monitor::MonitorLink::connect() {
|
||||||
|
|
||||||
mem_size = sizeof(SharedData) + sizeof(TriggerData);
|
mem_size = sizeof(SharedData) + sizeof(TriggerData);
|
||||||
|
|
||||||
Debug(1, "link.mem.size=%jd", mem_size);
|
Debug(1, "link.mem.size=%jd", static_cast<intmax_t>(mem_size));
|
||||||
#if ZM_MEM_MAPPED
|
#if ZM_MEM_MAPPED
|
||||||
map_fd = open(mem_file.c_str(), O_RDWR, (mode_t)0600);
|
map_fd = open(mem_file.c_str(), O_RDWR, (mode_t)0600);
|
||||||
if (map_fd < 0) {
|
if (map_fd < 0) {
|
||||||
|
@ -182,14 +182,14 @@ bool Monitor::MonitorLink::connect() {
|
||||||
disconnect();
|
disconnect();
|
||||||
return false;
|
return false;
|
||||||
} else if (map_stat.st_size < mem_size) {
|
} 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<intmax_t>(mem_size));
|
||||||
disconnect();
|
disconnect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0);
|
mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0);
|
||||||
if (mem_ptr == MAP_FAILED) {
|
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<intmax_t>(mem_size), strerror(errno));
|
||||||
disconnect();
|
disconnect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -947,7 +947,7 @@ bool Monitor::connect() {
|
||||||
map_fd = -1;
|
map_fd = -1;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} 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<intmax_t>(mem_size));
|
||||||
close(map_fd);
|
close(map_fd);
|
||||||
map_fd = -1;
|
map_fd = -1;
|
||||||
return false;
|
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);
|
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 (mem_ptr == MAP_FAILED) {
|
||||||
if (errno == EAGAIN) {
|
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<intmax_t>(mem_size));
|
||||||
#endif
|
#endif
|
||||||
mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0);
|
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<intmax_t>(mem_size));
|
||||||
#ifdef MAP_LOCKED
|
#ifdef MAP_LOCKED
|
||||||
} else {
|
} 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<intmax_t>(mem_size), strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ((mem_ptr == MAP_FAILED) or (mem_ptr == nullptr)) {
|
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<intmax_t>(mem_size), strerror(errno), errno);
|
||||||
close(map_fd);
|
close(map_fd);
|
||||||
map_fd = -1;
|
map_fd = -1;
|
||||||
mem_ptr = nullptr;
|
mem_ptr = nullptr;
|
||||||
|
@ -1656,7 +1656,7 @@ void Monitor::CheckAction() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monitor::UpdateCaptureFPS() {
|
void Monitor::UpdateFPS() {
|
||||||
if ( fps_report_interval and
|
if ( fps_report_interval and
|
||||||
(
|
(
|
||||||
!(image_count%fps_report_interval)
|
!(image_count%fps_report_interval)
|
||||||
|
@ -1675,82 +1675,35 @@ void Monitor::UpdateCaptureFPS() {
|
||||||
uint32 new_camera_bytes = camera->Bytes();
|
uint32 new_camera_bytes = camera->Bytes();
|
||||||
uint32 new_capture_bandwidth =
|
uint32 new_capture_bandwidth =
|
||||||
static_cast<uint32>((new_camera_bytes - last_camera_bytes) / elapsed.count());
|
static_cast<uint32>((new_camera_bytes - last_camera_bytes) / elapsed.count());
|
||||||
last_camera_bytes = new_camera_bytes;
|
double new_analysis_fps = (motion_frame_count - last_motion_frame_count) / elapsed.count();
|
||||||
|
|
||||||
Debug(4, "%s: %d - last %d = %d now:%lf, last %lf, elapsed %lf = %lffps",
|
Debug(4, "FPS: capture count %d - last capture count %d = %d now:%lf, last %lf, elapsed %lf = capture: %lf fps analysis: %lf fps",
|
||||||
"Capturing",
|
|
||||||
image_count,
|
image_count,
|
||||||
last_capture_image_count,
|
last_capture_image_count,
|
||||||
image_count - last_capture_image_count,
|
image_count - last_capture_image_count,
|
||||||
FPSeconds(now.time_since_epoch()).count(),
|
FPSeconds(now.time_since_epoch()).count(),
|
||||||
FPSeconds(last_analysis_fps_time.time_since_epoch()).count(),
|
FPSeconds(last_fps_time.time_since_epoch()).count(),
|
||||||
elapsed.count(),
|
elapsed.count(),
|
||||||
new_capture_fps);
|
new_capture_fps,
|
||||||
|
new_analysis_fps);
|
||||||
|
|
||||||
Info("%s: %d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec",
|
Info("%s: %d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec Analysing at %.2lf fps",
|
||||||
name.c_str(), image_count, new_capture_fps, new_capture_bandwidth);
|
name.c_str(), image_count, new_capture_fps, new_capture_bandwidth, new_analysis_fps);
|
||||||
|
|
||||||
shared_data->capture_fps = new_capture_fps;
|
shared_data->capture_fps = new_capture_fps;
|
||||||
last_fps_time = now;
|
last_fps_time = now;
|
||||||
last_capture_image_count = image_count;
|
last_capture_image_count = image_count;
|
||||||
|
shared_data->analysis_fps = new_analysis_fps;
|
||||||
|
last_motion_frame_count = motion_frame_count;
|
||||||
|
last_camera_bytes = new_camera_bytes;
|
||||||
|
|
||||||
std::string sql = stringtf(
|
std::string sql = stringtf(
|
||||||
"UPDATE LOW_PRIORITY Monitor_Status SET CaptureFPS = %.2lf, CaptureBandwidth=%u WHERE MonitorId=%u",
|
"UPDATE LOW_PRIORITY Monitor_Status SET CaptureFPS = %.2lf, CaptureBandwidth=%u, AnalysisFPS = %.2lf WHERE MonitorId=%u",
|
||||||
new_capture_fps, new_capture_bandwidth, id);
|
new_capture_fps, new_capture_bandwidth, new_analysis_fps, id);
|
||||||
dbQueue.push(std::move(sql));
|
dbQueue.push(std::move(sql));
|
||||||
} // now != last_fps_time
|
} // now != last_fps_time
|
||||||
} // end if report fps
|
} // end if report fps
|
||||||
} // void Monitor::UpdateCaptureFPS()
|
} // void Monitor::UpdateFPS()
|
||||||
|
|
||||||
void Monitor::UpdateAnalysisFPS() {
|
|
||||||
Debug(1, "analysis_image_count(%d) motion_count(%d) fps_report_interval(%d) mod%d",
|
|
||||||
analysis_image_count, motion_frame_count, fps_report_interval,
|
|
||||||
((analysis_image_count && fps_report_interval) ? !(analysis_image_count%fps_report_interval) : -1 ) );
|
|
||||||
|
|
||||||
if (
|
|
||||||
( analysis_image_count and fps_report_interval and !(analysis_image_count%fps_report_interval) )
|
|
||||||
or
|
|
||||||
// In startup do faster updates
|
|
||||||
( (analysis_image_count < fps_report_interval) and !(analysis_image_count%10) )
|
|
||||||
) {
|
|
||||||
SystemTimePoint now = std::chrono::system_clock::now();
|
|
||||||
|
|
||||||
FPSeconds elapsed = now - last_analysis_fps_time;
|
|
||||||
Debug(4, "%s: %d - now: %.2f, last %lf, diff %lf",
|
|
||||||
name.c_str(),
|
|
||||||
analysis_image_count,
|
|
||||||
FPSeconds(now.time_since_epoch()).count(),
|
|
||||||
FPSeconds(last_analysis_fps_time.time_since_epoch()).count(),
|
|
||||||
elapsed.count());
|
|
||||||
|
|
||||||
if (elapsed > Seconds(1)) {
|
|
||||||
double new_analysis_fps = (motion_frame_count - last_motion_frame_count) / elapsed.count();
|
|
||||||
Info("%s: %d - Analysing at %.2lf fps from %d - %d=%d / %lf - %lf = %lf",
|
|
||||||
name.c_str(),
|
|
||||||
analysis_image_count,
|
|
||||||
new_analysis_fps,
|
|
||||||
motion_frame_count,
|
|
||||||
last_motion_frame_count,
|
|
||||||
(motion_frame_count - last_motion_frame_count),
|
|
||||||
FPSeconds(now.time_since_epoch()).count(),
|
|
||||||
FPSeconds(last_analysis_fps_time.time_since_epoch()).count(),
|
|
||||||
elapsed.count());
|
|
||||||
|
|
||||||
if (new_analysis_fps != shared_data->analysis_fps) {
|
|
||||||
shared_data->analysis_fps = new_analysis_fps;
|
|
||||||
|
|
||||||
std::string sql = stringtf("UPDATE LOW_PRIORITY Monitor_Status SET AnalysisFPS = %.2lf WHERE MonitorId=%u",
|
|
||||||
new_analysis_fps, id);
|
|
||||||
dbQueue.push(std::move(sql));
|
|
||||||
last_analysis_fps_time = now;
|
|
||||||
last_motion_frame_count = motion_frame_count;
|
|
||||||
} else {
|
|
||||||
Debug(4, "No change in fps");
|
|
||||||
} // end if change in fps
|
|
||||||
} // end if at least 1 second has passed since last update
|
|
||||||
|
|
||||||
} // end if time to do an update
|
|
||||||
} // end void Monitor::UpdateAnalysisFPS
|
|
||||||
|
|
||||||
// Would be nice if this JUST did analysis
|
// Would be nice if this JUST did analysis
|
||||||
// This idea is that we should be analysing as close to the capture frame as possible.
|
// This idea is that we should be analysing as close to the capture frame as possible.
|
||||||
|
@ -1909,8 +1862,6 @@ bool Monitor::Analyse() {
|
||||||
Debug(3, "signal and active and modect");
|
Debug(3, "signal and active and modect");
|
||||||
Event::StringSet zoneSet;
|
Event::StringSet zoneSet;
|
||||||
|
|
||||||
int motion_score = last_motion_score;
|
|
||||||
|
|
||||||
if (analysis_fps_limit) {
|
if (analysis_fps_limit) {
|
||||||
double capture_fps = get_capture_fps();
|
double capture_fps = get_capture_fps();
|
||||||
motion_frame_skip = capture_fps / analysis_fps_limit;
|
motion_frame_skip = capture_fps / analysis_fps_limit;
|
||||||
|
@ -1927,7 +1878,7 @@ bool Monitor::Analyse() {
|
||||||
} else {
|
} else {
|
||||||
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.
|
||||||
motion_score = DetectMotion(*(snap->image), zoneSet);
|
int motion_score = DetectMotion(*(snap->image), zoneSet);
|
||||||
|
|
||||||
snap->zone_stats.reserve(zones.size());
|
snap->zone_stats.reserve(zones.size());
|
||||||
for (const Zone &zone : zones) {
|
for (const Zone &zone : zones) {
|
||||||
|
@ -1939,21 +1890,20 @@ 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, motion_score);
|
||||||
motion_frame_count += 1;
|
motion_frame_count += 1;
|
||||||
// Why are we updating the last_motion_score too?
|
|
||||||
last_motion_score = motion_score;
|
last_motion_score = motion_score;
|
||||||
|
if (motion_score) {
|
||||||
|
if (cause.length()) cause += ", ";
|
||||||
|
cause += MOTION_CAUSE;
|
||||||
|
noteSetMap[MOTION_CAUSE] = zoneSet;
|
||||||
|
} // end if motion_score
|
||||||
}
|
}
|
||||||
} 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
|
||||||
} else {
|
} 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 += last_motion_score;
|
||||||
score += motion_score;
|
|
||||||
if (cause.length()) cause += ", ";
|
|
||||||
cause += MOTION_CAUSE;
|
|
||||||
noteSetMap[MOTION_CAUSE] = zoneSet;
|
|
||||||
} // end if 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,
|
||||||
|
@ -1966,7 +1916,7 @@ 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 - GetVideoWriterStartTime() >= section_length)
|
if (section_length != Seconds(0) && (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>(timestamp.time_since_epoch()) % section_length == Seconds(0))) {
|
||||||
|
@ -1975,8 +1925,8 @@ bool Monitor::Analyse() {
|
||||||
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>(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>(event->StartTime().time_since_epoch()).count()),
|
||||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()),
|
static_cast<int64>(std::chrono::duration_cast<Seconds>(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
|
||||||
|
@ -2054,26 +2004,27 @@ bool Monitor::Analyse() {
|
||||||
} // end if ! event
|
} // end if ! event
|
||||||
} // end if RECORDING
|
} // end if RECORDING
|
||||||
|
|
||||||
if (score and (function == MODECT or function == NODECT)) {
|
if (score 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 - GetVideoWriterStartTime() >= min_section_length
|
&& ((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());
|
||||||
closeEvent();
|
closeEvent();
|
||||||
} else if (event) {
|
} 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
|
// 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,
|
Debug(3,
|
||||||
"pre_alarm_count in event %d, event frames %d, alarm frames %d event length %" PRIi64 " >=? %" PRIi64 " min",
|
"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(),
|
Event::PreAlarmCount(), pre_event_count,
|
||||||
event->Frames(),
|
event->Frames(),
|
||||||
event->AlarmFrames(),
|
event->AlarmFrames(),
|
||||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()),
|
static_cast<int64>(std::chrono::duration_cast<Seconds>(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));
|
||||||
}
|
}
|
||||||
if ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1)) {
|
if ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1)) {
|
||||||
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
||||||
|
@ -2170,8 +2121,10 @@ bool Monitor::Analyse() {
|
||||||
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;
|
||||||
} else if (state == ALERT) {
|
} else if (state == ALERT) {
|
||||||
if (analysis_image_count - last_alarm_count > post_event_count
|
if (
|
||||||
&& timestamp - GetVideoWriterStartTime() >= min_section_length) {
|
((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",
|
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 ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE )
|
//if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE )
|
||||||
|
@ -2189,7 +2142,8 @@ bool Monitor::Analyse() {
|
||||||
shared_data->state = state = ((function != MOCORD) ? IDLE : TAPE);
|
shared_data->state = state = ((function != MOCORD) ? IDLE : TAPE);
|
||||||
} else {
|
} else {
|
||||||
Debug(1,
|
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(),
|
State_Strings[state].c_str(),
|
||||||
analysis_image_count,
|
analysis_image_count,
|
||||||
last_alarm_count,
|
last_alarm_count,
|
||||||
|
@ -2208,18 +2162,15 @@ bool Monitor::Analyse() {
|
||||||
// Generate analysis images if necessary
|
// Generate analysis images if necessary
|
||||||
if ((savejpegs > 1) and snap->image) {
|
if ((savejpegs > 1) and snap->image) {
|
||||||
for (const Zone &zone : zones) {
|
for (const Zone &zone : zones) {
|
||||||
if (zone.Alarmed()) {
|
if (zone.Alarmed() and zone.AlarmImage()) {
|
||||||
if (zone.AlarmImage()) {
|
|
||||||
if (!snap->analysis_image)
|
if (!snap->analysis_image)
|
||||||
snap->analysis_image = new Image(*(snap->image));
|
snap->analysis_image = new Image(*(snap->image));
|
||||||
snap->analysis_image->Overlay(*(zone.AlarmImage()));
|
snap->analysis_image->Overlay(*(zone.AlarmImage()));
|
||||||
}
|
|
||||||
} // end if zone is alarmed
|
} // end if zone is alarmed
|
||||||
} // end foreach zone
|
} // end foreach zone
|
||||||
} // end if savejpegs
|
} // end if savejpegs
|
||||||
|
|
||||||
// incremement pre alarm image count
|
// incremement pre alarm image count
|
||||||
//have_pre_alarmed_frames ++;
|
|
||||||
Event::AddPreAlarmFrame(snap->image, timestamp, score, nullptr);
|
Event::AddPreAlarmFrame(snap->image, timestamp, score, nullptr);
|
||||||
} else if (state == ALARM) {
|
} else if (state == ALARM) {
|
||||||
for (const Zone &zone : zones) {
|
for (const Zone &zone : zones) {
|
||||||
|
@ -2234,7 +2185,7 @@ 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 - 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,
|
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>(timestamp.time_since_epoch()).count()),
|
||||||
|
@ -2299,8 +2250,6 @@ bool Monitor::Analyse() {
|
||||||
// Only do these if it's a video packet.
|
// Only do these if it's a video packet.
|
||||||
shared_data->last_read_index = snap->image_index;
|
shared_data->last_read_index = snap->image_index;
|
||||||
analysis_image_count++;
|
analysis_image_count++;
|
||||||
if (function == MODECT or function == MOCORD)
|
|
||||||
UpdateAnalysisFPS();
|
|
||||||
}
|
}
|
||||||
packetqueue.increment_it(analysis_it);
|
packetqueue.increment_it(analysis_it);
|
||||||
packetqueue.unlock(packet_lock);
|
packetqueue.unlock(packet_lock);
|
||||||
|
@ -2363,7 +2312,7 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
||||||
while ( 1 ) {
|
while ( 1 ) {
|
||||||
dest_ptr = link_id_str;
|
dest_ptr = link_id_str;
|
||||||
while ( *src_ptr >= '0' && *src_ptr <= '9' ) {
|
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++;
|
*dest_ptr++ = *src_ptr++;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -2585,7 +2534,6 @@ int Monitor::Capture() {
|
||||||
|
|
||||||
// Will only be queued if there are iterators allocated in the queue.
|
// Will only be queued if there are iterators allocated in the queue.
|
||||||
packetqueue.queuePacket(packet);
|
packetqueue.queuePacket(packet);
|
||||||
UpdateCaptureFPS();
|
|
||||||
} else { // result == 0
|
} else { // result == 0
|
||||||
// Question is, do we update last_write_index etc?
|
// Question is, do we update last_write_index etc?
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2625,7 +2573,7 @@ bool Monitor::Decode() {
|
||||||
//
|
//
|
||||||
//capture_image = packet->image = new Image(width, height, camera->Colours(), camera->SubpixelOrder());
|
//capture_image = packet->image = new Image(width, height, camera->Colours(), camera->SubpixelOrder());
|
||||||
int ret = packet->decode(camera->getVideoCodecContext());
|
int ret = packet->decode(camera->getVideoCodecContext());
|
||||||
if (ret > 0) {
|
if (ret > 0 and !zm_terminate) {
|
||||||
if (packet->in_frame and !packet->image) {
|
if (packet->in_frame and !packet->image) {
|
||||||
packet->image = new Image(camera_width, camera_height, camera->Colours(), camera->SubpixelOrder());
|
packet->image = new Image(camera_width, camera_height, camera->Colours(), camera->SubpixelOrder());
|
||||||
AVFrame *input_frame = packet->in_frame;
|
AVFrame *input_frame = packet->in_frame;
|
||||||
|
@ -2795,7 +2743,7 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
|
||||||
const char *s_ptr = label_time_text;
|
const char *s_ptr = label_time_text;
|
||||||
char *d_ptr = label_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] ) {
|
if ( *s_ptr == config.timestamp_code_char[0] ) {
|
||||||
bool found_macro = false;
|
bool found_macro = false;
|
||||||
switch ( *(s_ptr+1) ) {
|
switch ( *(s_ptr+1) ) {
|
||||||
|
@ -2811,7 +2759,7 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
|
||||||
typedef std::chrono::duration<int64, std::centi> Centiseconds;
|
typedef std::chrono::duration<int64, std::centi> Centiseconds;
|
||||||
Centiseconds centi_sec = std::chrono::duration_cast<Centiseconds>(
|
Centiseconds centi_sec = std::chrono::duration_cast<Centiseconds>(
|
||||||
ts_time.time_since_epoch() - std::chrono::duration_cast<Seconds>(ts_time.time_since_epoch()));
|
ts_time.time_since_epoch() - std::chrono::duration_cast<Seconds>(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<long long int>(centi_sec.count()));
|
||||||
found_macro = true;
|
found_macro = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ public:
|
||||||
} Deinterlace;
|
} Deinterlace;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UNKNOWN=-1,
|
UNKNOWN,
|
||||||
IDLE,
|
IDLE,
|
||||||
PREALARM,
|
PREALARM,
|
||||||
ALARM,
|
ALARM,
|
||||||
|
@ -546,8 +546,7 @@ public:
|
||||||
unsigned int GetLastWriteIndex() const;
|
unsigned int GetLastWriteIndex() const;
|
||||||
uint64_t GetLastEventId() const;
|
uint64_t GetLastEventId() const;
|
||||||
double GetFPS() const;
|
double GetFPS() const;
|
||||||
void UpdateAnalysisFPS();
|
void UpdateFPS();
|
||||||
void UpdateCaptureFPS();
|
|
||||||
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
|
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
|
||||||
void ForceAlarmOff();
|
void ForceAlarmOff();
|
||||||
void CancelForced();
|
void CancelForced();
|
||||||
|
|
|
@ -229,6 +229,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
|
||||||
break;
|
break;
|
||||||
case CMD_QUIT :
|
case CMD_QUIT :
|
||||||
Info("User initiated exit - CMD_QUIT");
|
Info("User initiated exit - CMD_QUIT");
|
||||||
|
zm_terminate = true;
|
||||||
break;
|
break;
|
||||||
case CMD_QUERY :
|
case CMD_QUERY :
|
||||||
Debug(1, "Got QUERY command, sending STATUS");
|
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);
|
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)
|
} // end void MonitorStream::processCommand(const CmdMsg *msg)
|
||||||
|
|
||||||
bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint timestamp) {
|
bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint timestamp) {
|
||||||
|
|
|
@ -209,7 +209,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||||
--it;
|
--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 (!keep_keyframes) {
|
||||||
// If not doing passthrough, we don't care about starting with a keyframe so logic is simpler
|
// If not doing passthrough, we don't care about starting with a keyframe so logic is simpler
|
||||||
|
|
|
@ -46,6 +46,7 @@ RETSIGTYPE zm_die_handler(int signal, siginfo_t * info, void *context)
|
||||||
RETSIGTYPE zm_die_handler(int signal)
|
RETSIGTYPE zm_die_handler(int signal)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
zm_terminate = true;
|
||||||
Error("Got signal %d (%s), crashing", signal, strsignal(signal));
|
Error("Got signal %d (%s), crashing", signal, strsignal(signal));
|
||||||
#if (defined(__i386__) || defined(__x86_64__))
|
#if (defined(__i386__) || defined(__x86_64__))
|
||||||
// Get more information if available
|
// Get more information if available
|
||||||
|
|
|
@ -619,7 +619,8 @@ VideoStore::~VideoStore() {
|
||||||
|
|
||||||
Debug(1, "Writing trailer");
|
Debug(1, "Writing trailer");
|
||||||
/* Write the trailer before close */
|
/* Write the trailer before close */
|
||||||
if (int rc = av_write_trailer(oc)) {
|
int rc;
|
||||||
|
if ((rc = av_write_trailer(oc)) < 0) {
|
||||||
Error("Error writing trailer %s", av_err2str(rc));
|
Error("Error writing trailer %s", av_err2str(rc));
|
||||||
} else {
|
} else {
|
||||||
Debug(3, "Success Writing trailer");
|
Debug(3, "Success Writing trailer");
|
||||||
|
@ -629,7 +630,7 @@ VideoStore::~VideoStore() {
|
||||||
if (!(out_format->flags & AVFMT_NOFILE)) {
|
if (!(out_format->flags & AVFMT_NOFILE)) {
|
||||||
/* Close the out file. */
|
/* Close the out file. */
|
||||||
Debug(4, "Closing");
|
Debug(4, "Closing");
|
||||||
if (int rc = avio_close(oc->pb)) {
|
if ((rc = avio_close(oc->pb)) < 0) {
|
||||||
Error("Error closing avio %s", av_err2str(rc));
|
Error("Error closing avio %s", av_err2str(rc));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -111,6 +111,13 @@ class VideoStore {
|
||||||
int writePacket(const std::shared_ptr<ZMPacket> &pkt);
|
int writePacket(const std::shared_ptr<ZMPacket> &pkt);
|
||||||
int write_packets(PacketQueue &queue);
|
int write_packets(PacketQueue &queue);
|
||||||
void flush_codecs();
|
void flush_codecs();
|
||||||
|
const char *get_codec() {
|
||||||
|
if (chosen_codec_data)
|
||||||
|
return chosen_codec_data->codec_codec;
|
||||||
|
if (video_out_stream)
|
||||||
|
return avcodec_get_name(video_out_stream->codecpar->codec_id);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_VIDEOSTORE_H
|
#endif // ZM_VIDEOSTORE_H
|
||||||
|
|
|
@ -268,7 +268,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
std::this_thread::sleep_for(sleep_time);
|
std::this_thread::sleep_for(sleep_time);
|
||||||
}
|
}
|
||||||
if (zm_terminate){
|
if (zm_terminate) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,6 +308,7 @@ int main(int argc, char *argv[]) {
|
||||||
result = -1;
|
result = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
monitors[i]->UpdateFPS();
|
||||||
|
|
||||||
// capture_delay is the amount of time we should sleep in useconds to achieve the desired framerate.
|
// capture_delay is the amount of time we should sleep in useconds to achieve the desired framerate.
|
||||||
Microseconds delay = (monitors[i]->GetState() == Monitor::ALARM) ? monitors[i]->GetAlarmCaptureDelay()
|
Microseconds delay = (monitors[i]->GetState() == Monitor::ALARM) ? monitors[i]->GetAlarmCaptureDelay()
|
||||||
|
|
|
@ -230,12 +230,11 @@ rm .gitignore
|
||||||
cd ../
|
cd ../
|
||||||
|
|
||||||
|
|
||||||
if [ !-e "$DIRECTORY.orig.tar.gz" ]; then
|
if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then
|
||||||
read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]"
|
read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]"
|
||||||
if [[ $REPLY == [yY] ]]; then
|
if [[ "$REPLY" == "" || "$REPLY" == [yY] ]]; then
|
||||||
|
|
||||||
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
|
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
|
||||||
fi;
|
fi;
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
|
IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
|
||||||
|
|
|
@ -93,7 +93,7 @@ if ( canView('Events') or canView('Snapshots') ) {
|
||||||
$exportFormat,
|
$exportFormat,
|
||||||
$exportCompress,
|
$exportCompress,
|
||||||
$exportStructure,
|
$exportStructure,
|
||||||
(!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport'),
|
(!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport')
|
||||||
)) {
|
)) {
|
||||||
ajaxResponse(array('exportFile'=>$exportFile));
|
ajaxResponse(array('exportFile'=>$exportFile));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -67,20 +67,19 @@ if (isset($_REQUEST['sort'])) {
|
||||||
|
|
||||||
// Offset specifies the starting row to return, used for pagination
|
// Offset specifies the starting row to return, used for pagination
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
if ( isset($_REQUEST['offset']) ) {
|
if (isset($_REQUEST['offset'])) {
|
||||||
if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) {
|
if ((!is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']))) {
|
||||||
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']);
|
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']);
|
||||||
} else {
|
} else {
|
||||||
$offset = $_REQUEST['offset'];
|
$offset = $_REQUEST['offset'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Limit specifies the number of rows to return
|
// Limit specifies the number of rows to return
|
||||||
// Set the default to 0 for events view, to prevent an issue with ALL pagination
|
// Set the default to 0 for events view, to prevent an issue with ALL pagination
|
||||||
$limit = 0;
|
$limit = 0;
|
||||||
if ( isset($_REQUEST['limit']) ) {
|
if (isset($_REQUEST['limit'])) {
|
||||||
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
if ((!is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']))) {
|
||||||
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
|
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
|
||||||
} else {
|
} else {
|
||||||
$limit = $_REQUEST['limit'];
|
$limit = $_REQUEST['limit'];
|
||||||
|
@ -91,25 +90,24 @@ if ( isset($_REQUEST['limit']) ) {
|
||||||
// MAIN LOOP
|
// MAIN LOOP
|
||||||
//
|
//
|
||||||
|
|
||||||
switch ( $task ) {
|
switch ($task) {
|
||||||
case 'archive' :
|
case 'archive' :
|
||||||
foreach ( $eids as $eid ) archiveRequest($task, $eid);
|
foreach ($eids as $eid) archiveRequest($task, $eid);
|
||||||
break;
|
break;
|
||||||
case 'unarchive' :
|
case 'unarchive' :
|
||||||
# The idea is that anyone can archive, but only people with Event Edit permission can 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']);
|
ajaxError('Insufficient permissions for user '.$user['Username']);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ( $eids as $eid ) archiveRequest($task, $eid);
|
foreach ($eids as $eid) archiveRequest($task, $eid);
|
||||||
break;
|
break;
|
||||||
case 'delete' :
|
case 'delete' :
|
||||||
if ( !canEdit('Events') ) {
|
if (!canEdit('Events')) {
|
||||||
ajaxError('Insufficient permissions for user '.$user['Username']);
|
ajaxError('Insufficient permissions for user '.$user['Username']);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
foreach ($eids as $eid) $data[] = deleteRequest($eid);
|
||||||
foreach ( $eids as $eid ) $data[] = deleteRequest($eid);
|
|
||||||
break;
|
break;
|
||||||
case 'query' :
|
case 'query' :
|
||||||
$data = queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit);
|
$data = queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit);
|
||||||
|
@ -139,6 +137,8 @@ function deleteRequest($eid) {
|
||||||
$message[] = array($eid=>'Event not found.');
|
$message[] = array($eid=>'Event not found.');
|
||||||
} else if ( $event->Archived() ) {
|
} else if ( $event->Archived() ) {
|
||||||
$message[] = array($eid=>'Event is archived, cannot delete it.');
|
$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 {
|
} else {
|
||||||
$event->delete();
|
$event->delete();
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,6 @@ function deleteRequest($eid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit) {
|
function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit) {
|
||||||
|
|
||||||
$data = array(
|
$data = array(
|
||||||
'total' => 0,
|
'total' => 0,
|
||||||
'totalNotFiltered' => 0,
|
'totalNotFiltered' => 0,
|
||||||
|
@ -156,7 +155,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
|
||||||
);
|
);
|
||||||
|
|
||||||
$failed = !$filter->test_pre_sql_conditions();
|
$failed = !$filter->test_pre_sql_conditions();
|
||||||
if ( $failed ) {
|
if ($failed) {
|
||||||
ZM\Debug('Pre conditions failed, not doing sql');
|
ZM\Debug('Pre conditions failed, not doing sql');
|
||||||
return $data;
|
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
|
// The names of columns shown in the event view that are NOT dB columns in the database
|
||||||
$col_alt = array('Monitor', 'Storage');
|
$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);
|
ZM\Error('Invalid sort field: ' . $sort);
|
||||||
$sort = 'Id';
|
$sort = 'Id';
|
||||||
}
|
}
|
||||||
|
@ -186,7 +185,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
|
||||||
|
|
||||||
$storage_areas = ZM\Storage::find();
|
$storage_areas = ZM\Storage::find();
|
||||||
$StorageById = array();
|
$StorageById = array();
|
||||||
foreach ( $storage_areas as $S ) {
|
foreach ($storage_areas as $S) {
|
||||||
$StorageById[$S->Id()] = $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);
|
ZM\Debug('Calling the following sql query: ' .$sql);
|
||||||
$query = dbQuery($sql, $values);
|
$query = dbQuery($sql, $values);
|
||||||
if ( $query ) {
|
if (!$query) {
|
||||||
while ( $row = dbFetchNext($query) ) {
|
ajaxError(dbError($sql));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ($row = dbFetchNext($query)) {
|
||||||
$event = new ZM\Event($row);
|
$event = new ZM\Event($row);
|
||||||
$event->remove_from_cache();
|
$event->remove_from_cache();
|
||||||
if ( !$filter->test_post_sql_conditions($event) ) {
|
if (!$filter->test_post_sql_conditions($event)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$event_ids[] = $event->Id();
|
$event_ids[] = $event->Id();
|
||||||
$unfiltered_rows[] = $row;
|
$unfiltered_rows[] = $row;
|
||||||
} # end foreach row
|
} # end foreach row
|
||||||
}
|
|
||||||
|
|
||||||
ZM\Debug('Have ' . count($unfiltered_rows) . ' events matching base filter.');
|
ZM\Debug('Have ' . count($unfiltered_rows) . ' events matching base filter.');
|
||||||
|
|
||||||
$filtered_rows = null;
|
$filtered_rows = null;
|
||||||
|
|
||||||
if ( count($advsearch) or $search != '' ) {
|
if (count($advsearch) or $search != '') {
|
||||||
$search_filter = new ZM\Filter();
|
$search_filter = new ZM\Filter();
|
||||||
$search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$event_ids));
|
$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
|
// 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
|
// Making an exuctive decision to ignore the normal search, when advanced search is in use
|
||||||
// Alternatively we could try to do both
|
// Alternatively we could try to do both
|
||||||
if ( count($advsearch) ) {
|
if (count($advsearch)) {
|
||||||
$terms = array();
|
$terms = array();
|
||||||
foreach ( $advsearch as $col=>$text ) {
|
foreach ($advsearch as $col=>$text) {
|
||||||
$terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text);
|
$terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text);
|
||||||
} # end foreach col in advsearch
|
} # end foreach col in advsearch
|
||||||
$terms[0]['obr'] = 1;
|
$terms[0]['obr'] = 1;
|
||||||
$terms[count($terms)-1]['cbr'] = 1;
|
$terms[count($terms)-1]['cbr'] = 1;
|
||||||
$search_filter->addTerms($terms);
|
$search_filter->addTerms($terms);
|
||||||
} else if ( $search != '' ) {
|
} else if ($search != '') {
|
||||||
$search = '%' .$search. '%';
|
$search = '%' .$search. '%';
|
||||||
$terms = array();
|
$terms = array();
|
||||||
foreach ( $columns as $col ) {
|
foreach ($columns as $col) {
|
||||||
$terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search);
|
$terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search);
|
||||||
}
|
}
|
||||||
$terms[0]['obr'] = 1;
|
$terms[0]['obr'] = 1;
|
||||||
|
@ -239,15 +240,17 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
|
||||||
} # end if search
|
} # end if search
|
||||||
|
|
||||||
$sql = 'SELECT ' .$col_str. ' FROM `Events` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order;
|
$sql = 'SELECT ' .$col_str. ' FROM `Events` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order;
|
||||||
ZM\Debug('Calling the following sql query: ' .$sql);
|
|
||||||
$filtered_rows = dbFetchAll($sql);
|
$filtered_rows = dbFetchAll($sql);
|
||||||
ZM\Debug('Have ' . count($filtered_rows) . ' events matching search filter.');
|
ZM\Debug('Have ' . count($filtered_rows) . ' events matching search filter: '.$sql);
|
||||||
} else {
|
} else {
|
||||||
$filtered_rows = $unfiltered_rows;
|
$filtered_rows = $unfiltered_rows;
|
||||||
} # end if search_filter->terms() > 1
|
} # end if search_filter->terms() > 1
|
||||||
|
|
||||||
|
if ($limit)
|
||||||
|
$filtered_rows = array_slice($filtered_rows, $offset, $limit);
|
||||||
|
|
||||||
$returned_rows = array();
|
$returned_rows = array();
|
||||||
foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) {
|
foreach ($filtered_rows as $row) {
|
||||||
$event = new ZM\Event($row);
|
$event = new ZM\Event($row);
|
||||||
|
|
||||||
$scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width());
|
$scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width());
|
||||||
|
|
|
@ -38,7 +38,7 @@ if ($zmuOutput) {
|
||||||
$ctls = shell_exec('v4l2-ctl -d '.$monitor->Device().' --list-ctrls');
|
$ctls = shell_exec('v4l2-ctl -d '.$monitor->Device().' --list-ctrls');
|
||||||
|
|
||||||
if (!$ctls) {
|
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 = '
|
$ctls = '
|
||||||
brightness 0x00980900 (int) : min=-10 max=10 step=1 default=0 value=8
|
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
|
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') {
|
if ($setting == 'brightness' or $setting == 'colour' or $setting == 'contrast' or $setting == 'hue') {
|
||||||
echo '
|
echo '
|
||||||
<tr>
|
<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>
|
<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>
|
</tr>
|
||||||
';
|
';
|
||||||
|
@ -94,7 +99,7 @@ foreach ($ctls as $line) {
|
||||||
if ($type == '(bool)') {
|
if ($type == '(bool)') {
|
||||||
echo '
|
echo '
|
||||||
<tr>
|
<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>'.html_radio('new'.$setting_uc, array('0'=>translate('True'), '1', translate('False')), $value, array('disabled'=>'disabled')).'
|
||||||
</td><td></td>
|
</td><td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -102,14 +107,14 @@ foreach ($ctls as $line) {
|
||||||
} else if ($type == '(int)') {
|
} else if ($type == '(int)') {
|
||||||
echo '
|
echo '
|
||||||
<tr>
|
<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>
|
<td></td><td><input type="range" '.$ctl[1].' disabled="disabled"/></td><td></td>
|
||||||
</tr>
|
</tr>
|
||||||
';
|
';
|
||||||
} else {
|
} else {
|
||||||
echo '
|
echo '
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">'.translate($setting_uc).'</th>
|
<th scope="row">'.$label.'</th>
|
||||||
<td></td><td>'.$value.'</td><td></td>
|
<td></td><td>'.$value.'</td><td></td>
|
||||||
</tr>
|
</tr>
|
||||||
';
|
';
|
||||||
|
|
|
@ -495,6 +495,10 @@ class Monitor extends ZM_Object {
|
||||||
return $this->Server()->UrlToIndex($port);
|
return $this->Server()->UrlToIndex($port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function UrlToZMS($port=null) {
|
||||||
|
return $this->Server()->UrlToZMS($port).'?mid='.$this->Id();
|
||||||
|
}
|
||||||
|
|
||||||
public function sendControlCommand($command) {
|
public function sendControlCommand($command) {
|
||||||
// command is generally a command option list like --command=blah but might be just the word quit
|
// command is generally a command option list like --command=blah but might be just the word quit
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ function dbLog($sql, $update=false) {
|
||||||
function dbError($sql) {
|
function dbError($sql) {
|
||||||
global $dbConn;
|
global $dbConn;
|
||||||
$error = $dbConn->errorInfo();
|
$error = $dbConn->errorInfo();
|
||||||
if ( !$error[0] )
|
if (!$error[0])
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
$message = "SQL-ERR '".implode("\n", $dbConn->errorInfo())."', statement was '".$sql."'";
|
$message = "SQL-ERR '".implode("\n", $dbConn->errorInfo())."', statement was '".$sql."'";
|
||||||
|
@ -130,17 +130,17 @@ function dbEscape( $string ) {
|
||||||
|
|
||||||
function dbQuery($sql, $params=NULL, $debug = false) {
|
function dbQuery($sql, $params=NULL, $debug = false) {
|
||||||
global $dbConn;
|
global $dbConn;
|
||||||
if ( dbLog($sql, true) )
|
if (dbLog($sql, true))
|
||||||
return;
|
return;
|
||||||
$result = NULL;
|
$result = NULL;
|
||||||
try {
|
try {
|
||||||
if ( isset($params) ) {
|
if (isset($params)) {
|
||||||
if ( ! $result = $dbConn->prepare($sql) ) {
|
if (!$result = $dbConn->prepare($sql)) {
|
||||||
ZM\Error("SQL: Error preparing $sql: " . $pdo->errorInfo);
|
ZM\Error("SQL: Error preparing $sql: " . $pdo->errorInfo);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $result->execute($params) ) {
|
if (!$result->execute($params)) {
|
||||||
ZM\Error("SQL: Error executing $sql: " . print_r($result->errorInfo(), true));
|
ZM\Error("SQL: Error executing $sql: " . print_r($result->errorInfo(), true));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,10 @@ function MonitorStream(monitorData) {
|
||||||
this.id = monitorData.id;
|
this.id = monitorData.id;
|
||||||
this.connKey = monitorData.connKey;
|
this.connKey = monitorData.connKey;
|
||||||
this.url = monitorData.url;
|
this.url = monitorData.url;
|
||||||
|
this.url_to_zms = monitorData.url_to_zms;
|
||||||
this.width = monitorData.width;
|
this.width = monitorData.width;
|
||||||
this.height = monitorData.height;
|
this.height = monitorData.height;
|
||||||
|
this.scale = 100;
|
||||||
this.status = null;
|
this.status = null;
|
||||||
this.alarmState = STATE_IDLE;
|
this.alarmState = STATE_IDLE;
|
||||||
this.lastAlarmState = STATE_IDLE;
|
this.lastAlarmState = STATE_IDLE;
|
||||||
|
@ -15,19 +17,68 @@ function MonitorStream(monitorData) {
|
||||||
};
|
};
|
||||||
this.type = monitorData.type;
|
this.type = monitorData.type;
|
||||||
this.refresh = monitorData.refresh;
|
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) {
|
this.start = function(delay) {
|
||||||
// Step 1 make sure we are streaming instead of a static image
|
// Step 1 make sure we are streaming instead of a static image
|
||||||
var stream = $j('#liveStream'+this.id);
|
const stream = this.getElement();
|
||||||
if (!stream.length) {
|
if (!stream) return;
|
||||||
console.log('No live stream');
|
|
||||||
return;
|
if (!stream.src) {
|
||||||
}
|
|
||||||
stream = stream[0];
|
|
||||||
if ( !stream ) {
|
|
||||||
console.log('No live stream');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( !stream.src ) {
|
|
||||||
// Website Monitors won't have an img tag
|
// Website Monitors won't have an img tag
|
||||||
console.log('No src for #liveStream'+this.id);
|
console.log('No src for #liveStream'+this.id);
|
||||||
console.log(stream);
|
console.log(stream);
|
||||||
|
@ -38,7 +89,7 @@ function MonitorStream(monitorData) {
|
||||||
src += '&connkey='+this.connKey;
|
src += '&connkey='+this.connKey;
|
||||||
}
|
}
|
||||||
if ( stream.src != src ) {
|
if ( stream.src != src ) {
|
||||||
console.log("Setting to streaming");
|
console.log("Setting to streaming: " + src);
|
||||||
stream.src = '';
|
stream.src = '';
|
||||||
stream.src = src;
|
stream.src = src;
|
||||||
}
|
}
|
||||||
|
|
|
@ -916,7 +916,7 @@ function xhtmlFooter() {
|
||||||
?>
|
?>
|
||||||
<script src="<?php echo cache_bust('skins/'.$skin.'/js/jquery.min.js'); ?>"></script>
|
<script src="<?php echo cache_bust('skins/'.$skin.'/js/jquery.min.js'); ?>"></script>
|
||||||
<script src="skins/<?php echo $skin; ?>/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
|
<script src="skins/<?php echo $skin; ?>/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
|
||||||
<script src="<?php echo cache_bust('skins/'.$skin.'/js/bootstrap.min.js'); ?>"></script>
|
<script src="skins/<?php echo $skin; ?>/js/bootstrap-4.5.0.min.js"></script>
|
||||||
<?php echo output_script_if_exists(array(
|
<?php echo output_script_if_exists(array(
|
||||||
'js/tableExport.min.js',
|
'js/tableExport.min.js',
|
||||||
'js/bootstrap-table.min.js',
|
'js/bootstrap-table.min.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
|
$j(window).on('resize', endOfResize); //set delayed scaling when Scale to Fit is selected
|
||||||
var ratio = baseWidth / baseHeight;
|
var ratio = baseWidth / baseHeight;
|
||||||
var container = $j('#content');
|
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);
|
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);
|
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));
|
var newHeight = viewPort.height() - (bottomLoc - scaleEl.outerHeight(true));
|
||||||
|
//console.log("newHeight = " + viewPort.height() +" - " + bottomLoc + ' - ' + scaleEl.outerHeight(true));
|
||||||
var newWidth = ratio * newHeight;
|
var newWidth = ratio * newHeight;
|
||||||
if (newWidth > container.innerWidth()) {
|
if (newWidth > container.innerWidth()) {
|
||||||
newWidth = container.innerWidth();
|
newWidth = container.innerWidth();
|
||||||
|
@ -598,13 +609,15 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) {
|
||||||
return parseInt($j(this).val());
|
return parseInt($j(this).val());
|
||||||
}).get();
|
}).get();
|
||||||
scales.shift();
|
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.
|
$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)) {
|
if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) {
|
||||||
closest = this.valueOf();
|
closest = this.valueOf();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (closest) {
|
||||||
autoScale = closest;
|
autoScale = closest;
|
||||||
|
}
|
||||||
return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale};
|
return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,3 +960,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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ foreach ( $perms as $perm ) {
|
||||||
?>
|
?>
|
||||||
|
|
||||||
var ANIMATE_THUMBS = <?php echo ZM_WEB_ANIMATE_THUMBS?'true':'false' ?>;
|
var ANIMATE_THUMBS = <?php echo ZM_WEB_ANIMATE_THUMBS?'true':'false' ?>;
|
||||||
|
var SCALE_BASE = <?php echo SCALE_BASE ?>;
|
||||||
|
|
||||||
var refreshParent = <?php
|
var refreshParent = <?php
|
||||||
if ( ! empty($refreshParent) ) {
|
if ( ! empty($refreshParent) ) {
|
||||||
|
|
|
@ -300,7 +300,7 @@ function getCmdResponse(respObj, respText) {
|
||||||
|
|
||||||
if (streamStatus.auth) {
|
if (streamStatus.auth) {
|
||||||
// Try to reload the image stream.
|
// Try to reload the image stream.
|
||||||
var streamImg = $j('#evtStream');
|
var streamImg = document.getElementById('evtStream');
|
||||||
if (streamImg) {
|
if (streamImg) {
|
||||||
streamImg.src = streamImg.src.replace(/auth=\w+/i, 'auth='+streamStatus.auth);
|
streamImg.src = streamImg.src.replace(/auth=\w+/i, 'auth='+streamStatus.auth);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,16 @@ var params =
|
||||||
|
|
||||||
// Called by bootstrap-table to retrieve zm event data
|
// Called by bootstrap-table to retrieve zm event data
|
||||||
function ajaxRequest(params) {
|
function ajaxRequest(params) {
|
||||||
if ( params.data && params.data.filter ) {
|
if (params.data && params.data.filter) {
|
||||||
params.data.advsearch = params.data.filter;
|
params.data.advsearch = params.data.filter;
|
||||||
delete params.data.filter;
|
delete params.data.filter;
|
||||||
}
|
}
|
||||||
$j.getJSON(thisUrl + '?view=request&request=events&task=query'+filterQuery, params.data)
|
$j.getJSON(thisUrl + '?view=request&request=events&task=query'+filterQuery, params.data)
|
||||||
.done(function(data) {
|
.done(function(data) {
|
||||||
|
if (data.result == 'Error') {
|
||||||
|
alert(data.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var rows = processRows(data.rows);
|
var rows = processRows(data.rows);
|
||||||
// rearrange the result into what bootstrap-table expects
|
// rearrange the result into what bootstrap-table expects
|
||||||
params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows});
|
params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows});
|
||||||
|
|
|
@ -317,5 +317,10 @@ function initPage() {
|
||||||
}
|
}
|
||||||
selectLayout('#zmMontageLayout');
|
selectLayout('#zmMontageLayout');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function watchFullscreen() {
|
||||||
|
const content = document.getElementById('content');
|
||||||
|
openFullscreen(content);
|
||||||
|
}
|
||||||
// Kick everything off
|
// Kick everything off
|
||||||
$j(document).ready(initPage);
|
$j(document).ready(initPage);
|
||||||
|
|
|
@ -16,6 +16,9 @@ function generateVideoResponse( data, responseText ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateVideo() {
|
function generateVideo() {
|
||||||
|
$j.ajaxSetup({
|
||||||
|
timeout: 0
|
||||||
|
});
|
||||||
var form = $j('#videoForm').serialize();
|
var form = $j('#videoForm').serialize();
|
||||||
$j.getJSON(thisUrl + '?view=request&request=event&action=video', form)
|
$j.getJSON(thisUrl + '?view=request&request=event&action=video', form)
|
||||||
.done(generateVideoResponse)
|
.done(generateVideoResponse)
|
||||||
|
|
|
@ -970,5 +970,20 @@ function initPage() {
|
||||||
});
|
});
|
||||||
} // initPage
|
} // initPage
|
||||||
|
|
||||||
|
function watchFullscreen() {
|
||||||
|
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
|
// Kick everything off
|
||||||
$j(document).ready(initPage);
|
$j(document).ready(initPage);
|
||||||
|
|
|
@ -97,9 +97,13 @@ foreach( dbFetchAll( 'SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, a
|
||||||
$labels[$row['Preset']] = $row['Label'];
|
$labels[$row['Preset']] = $row['Label'];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( $labels as $index=>$label ) {
|
foreach ($labels as $index=>$label) {
|
||||||
?>
|
?>
|
||||||
labels[<?php echo validInt($index) ?>] = '<?php echo validJsStr($label) ?>';
|
labels[<?php echo validInt($index) ?>] = '<?php echo validJsStr($label) ?>';
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
var translate = {
|
||||||
|
"Fullscreen": "<?php echo translate('Fullscreen') ?>",
|
||||||
|
"Exit Fullscreen": "<?php echo translate('Exit Fullscreen') ?>",
|
||||||
|
};
|
||||||
|
|
|
@ -661,6 +661,7 @@ function initPage() {
|
||||||
|
|
||||||
// Start the fps and status updates. give a random delay so that we don't assault the server
|
// 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 );
|
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
|
||||||
|
monitors[i].setScale('auto');
|
||||||
monitors[i].start(delay);
|
monitors[i].start(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ monitorData[monitorData.length] = {
|
||||||
'width': <?php echo $monitor->ViewWidth() ?>,
|
'width': <?php echo $monitor->ViewWidth() ?>,
|
||||||
'height':<?php echo $monitor->ViewHeight() ?>,
|
'height':<?php echo $monitor->ViewHeight() ?>,
|
||||||
'url': '<?php echo $monitor->UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
'url': '<?php echo $monitor->UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
||||||
|
'url_to_zms': '<?php echo $monitor->UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
||||||
'type': '<?php echo $monitor->Type() ?>',
|
'type': '<?php echo $monitor->Type() ?>',
|
||||||
'refresh': '<?php echo $monitor->Refresh() ?>'
|
'refresh': '<?php echo $monitor->Refresh() ?>'
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@ function initPage() {
|
||||||
|
|
||||||
// Start the fps and status updates. give a random delay so that we don't assault the server
|
// 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 );
|
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
|
||||||
|
monitors[i].setScale('auto');
|
||||||
monitors[i].start(delay);
|
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);
|
window.addEventListener('DOMContentLoaded', initPage);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ monitorData[monitorData.length] = {
|
||||||
'width': <?php echo $monitor->ViewWidth() ?>,
|
'width': <?php echo $monitor->ViewWidth() ?>,
|
||||||
'height':<?php echo $monitor->ViewHeight() ?>,
|
'height':<?php echo $monitor->ViewHeight() ?>,
|
||||||
'url': '<?php echo $monitor->UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
'url': '<?php echo $monitor->UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
||||||
|
'url_to_zms': '<?php echo $monitor->UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
||||||
'type': '<?php echo $monitor->Type() ?>',
|
'type': '<?php echo $monitor->Type() ?>',
|
||||||
'refresh': '<?php echo $monitor->Refresh() ?>'
|
'refresh': '<?php echo $monitor->Refresh() ?>'
|
||||||
};
|
};
|
||||||
|
@ -24,7 +25,7 @@ var STATE_TAPE = <?php echo STATE_TAPE ?>;
|
||||||
|
|
||||||
var stateStrings = new Array();
|
var stateStrings = new Array();
|
||||||
stateStrings[STATE_IDLE] = "<?php echo translate('Idle') ?>";
|
stateStrings[STATE_IDLE] = "<?php echo translate('Idle') ?>";
|
||||||
stateStrings[STATE_PREALARM] = "<?php echo translate('Idle') ?>";
|
stateStrings[STATE_PREALARM] = "<?php echo translate('PreAlarm') ?>";
|
||||||
stateStrings[STATE_ALARM] = "<?php echo translate('Alarm') ?>";
|
stateStrings[STATE_ALARM] = "<?php echo translate('Alarm') ?>";
|
||||||
stateStrings[STATE_ALERT] = "<?php echo translate('Alert') ?>";
|
stateStrings[STATE_ALERT] = "<?php echo translate('Alert') ?>";
|
||||||
stateStrings[STATE_TAPE] = "<?php echo translate('Record') ?>";
|
stateStrings[STATE_TAPE] = "<?php echo translate('Record') ?>";
|
||||||
|
|
|
@ -461,9 +461,12 @@ switch ( $name ) {
|
||||||
<tr class="Id">
|
<tr class="Id">
|
||||||
<td class="text-right pr-3"><?php echo translate('Id') ?></td>
|
<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/>
|
<td><input type="number" step="1" min="1" name="newMonitor[Id]" placeholder="leave blank for auto"/><br/>
|
||||||
10 Available Ids:
|
<?php
|
||||||
<?php echo implode(', ', array_slice($available_monitor_ids, 0, 10)); ?>
|
if (count($available_monitor_ids)) {
|
||||||
</td>
|
echo 'Some available ids: '.implode(', ', array_slice($available_monitor_ids, 0, 10));
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,9 @@ if ( canView('System') ) {
|
||||||
<?php echo translate('Snapshot') ?>
|
<?php echo translate('Snapshot') ?>
|
||||||
</button>
|
</button>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
<button type="button" id="fullscreenBtn" title="<?php echo translate('Fullscreen') ?>" class="avail" data-on-click="watchFullscreen">
|
||||||
|
<i class="material-icons md-18">fullscreen</i>
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -142,6 +142,9 @@ if ( $streamMode == 'jpeg' ) {
|
||||||
<button type="button" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" data-on-click="streamCmdZoomOut">
|
<button type="button" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" data-on-click="streamCmdZoomOut">
|
||||||
<i class="material-icons md-18">zoom_out</i>
|
<i class="material-icons md-18">zoom_out</i>
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" id="fullscreenBtn" title="<?php echo translate('Fullscreen') ?>" class="avail" data-on-click="watchFullscreen">
|
||||||
|
<i class="material-icons md-18">fullscreen</i>
|
||||||
|
</button>
|
||||||
<?php
|
<?php
|
||||||
} // end if streamMode==jpeg
|
} // end if streamMode==jpeg
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -80,11 +80,10 @@ xhtmlHeaders(__FILE__, translate('Zones'));
|
||||||
<?php echo getStreamHTML($monitor, $options); ?>
|
<?php echo getStreamHTML($monitor, $options); ?>
|
||||||
<svg class="zones" viewBox="0 0 <?php echo $monitor->ViewWidth().' '.$monitor->ViewHeight() ?>">
|
<svg class="zones" viewBox="0 0 <?php echo $monitor->ViewWidth().' '.$monitor->ViewHeight() ?>">
|
||||||
<?php
|
<?php
|
||||||
foreach( array_reverse($zones) as $zone ) {
|
foreach (array_reverse($zones) as $zone) {
|
||||||
?>
|
?>
|
||||||
<polygon points="<?php echo $zone['AreaCoords'] ?>"
|
<polygon points="<?php echo $zone['AreaCoords'] ?>"
|
||||||
class="zmlink <?php echo $zone['Type']?>"
|
class="zmlink <?php echo $zone['Type']?>"
|
||||||
data-on-click-true="streamCmdQuit"
|
|
||||||
data-url="?view=zone&mid=<?php echo $mid ?>&zid=<?php echo $zone['Id'] ?>"
|
data-url="?view=zone&mid=<?php echo $mid ?>&zid=<?php echo $zone['Id'] ?>"
|
||||||
/>
|
/>
|
||||||
<?php
|
<?php
|
||||||
|
@ -126,7 +125,7 @@ xhtmlHeaders(__FILE__, translate('Zones'));
|
||||||
<button type="submit" name="deleteBtn" value="Delete" disabled="disabled"><?php echo translate('Delete') ?></button>
|
<button type="submit" name="deleteBtn" value="Delete" disabled="disabled"><?php echo translate('Delete') ?></button>
|
||||||
</div>
|
</div>
|
||||||
</div><!--zones-->
|
</div><!--zones-->
|
||||||
<br class="clear"/>
|
<br class="clear"/>
|
||||||
</div><!--Monitor-->
|
</div><!--Monitor-->
|
||||||
<?php
|
<?php
|
||||||
} # end foreach monitor
|
} # end foreach monitor
|
||||||
|
|
Loading…
Reference in New Issue