Merge branch 'master' of github.com:ZoneMinder/zoneminder
This commit is contained in:
commit
6d30f5431b
|
@ -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
|
||||
|
|
|
@ -255,7 +255,7 @@ void zmDbQueue::process() {
|
|||
Logger *log = Logger::fetch();
|
||||
Logger::Level db_level = log->databaseLevel();
|
||||
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);
|
||||
}
|
||||
std::string sql = mQueue.front();
|
||||
|
|
100
src/zm_event.cpp
100
src/zm_event.cpp
|
@ -60,8 +60,8 @@ Event::Event(
|
|||
//snapshit_file(),
|
||||
//alarm_file(""),
|
||||
videoStore(nullptr),
|
||||
//video_name(""),
|
||||
//video_file(""),
|
||||
//video_path(""),
|
||||
last_db_frame(0),
|
||||
have_video_keyframe(false),
|
||||
//scheme
|
||||
|
@ -103,7 +103,14 @@ Event::Event(
|
|||
|
||||
// Copy it in case opening the mp4 doesn't work we can set it to another value
|
||||
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(
|
||||
"INSERT INTO `Events` "
|
||||
|
@ -120,28 +127,28 @@ Event::Event(
|
|||
state_id,
|
||||
monitor->getOrientation(),
|
||||
0,
|
||||
"",
|
||||
video_incomplete_file.c_str(),
|
||||
save_jpegs,
|
||||
storage->SchemeString().c_str()
|
||||
);
|
||||
id = zmDbDoInsert(sql);
|
||||
|
||||
if ( !SetPath(storage) ) {
|
||||
if (!SetPath(storage)) {
|
||||
// Try another
|
||||
Warning("Failed creating event dir at %s", storage->Path());
|
||||
|
||||
sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id());
|
||||
if ( monitor->ServerId() )
|
||||
if (monitor->ServerId())
|
||||
sql += stringtf(" AND ServerId=%u", monitor->ServerId());
|
||||
|
||||
Debug(1, "%s", sql.c_str());
|
||||
delete storage;
|
||||
storage = nullptr;
|
||||
|
||||
MYSQL_RES *result = zmDbFetch(sql);
|
||||
if ( result ) {
|
||||
for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
||||
if (result) {
|
||||
for (int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) {
|
||||
storage = new Storage(atoi(dbrow[0]));
|
||||
if ( SetPath(storage) )
|
||||
if (SetPath(storage))
|
||||
break;
|
||||
delete storage;
|
||||
storage = nullptr;
|
||||
|
@ -149,18 +156,18 @@ Event::Event(
|
|||
mysql_free_result(result);
|
||||
result = nullptr;
|
||||
}
|
||||
if ( !storage ) {
|
||||
if (!storage) {
|
||||
Info("No valid local storage area found. Trying all other areas.");
|
||||
// Try remote
|
||||
sql = "SELECT `Id` FROM `Storage` WHERE ServerId IS NULL";
|
||||
if ( monitor->ServerId() )
|
||||
if (monitor->ServerId())
|
||||
sql += stringtf(" OR ServerId != %u", monitor->ServerId());
|
||||
|
||||
result = zmDbFetch(sql);
|
||||
if ( result ) {
|
||||
if (result) {
|
||||
for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
||||
storage = new Storage(atoi(dbrow[0]));
|
||||
if ( SetPath(storage) )
|
||||
if (SetPath(storage))
|
||||
break;
|
||||
delete storage;
|
||||
storage = nullptr;
|
||||
|
@ -169,7 +176,7 @@ Event::Event(
|
|||
result = nullptr;
|
||||
}
|
||||
}
|
||||
if ( !storage ) {
|
||||
if (!storage) {
|
||||
storage = new Storage();
|
||||
Warning("Failed to find a storage area to save events.");
|
||||
}
|
||||
|
@ -178,24 +185,16 @@ Event::Event(
|
|||
} // end if ! setPath(Storage)
|
||||
Debug(1, "Using storage area at %s", path.c_str());
|
||||
|
||||
video_name = "";
|
||||
|
||||
snapshot_file = path + "/snapshot.jpg";
|
||||
alarm_file = path + "/alarm.jpg";
|
||||
|
||||
/* Save as video */
|
||||
video_incomplete_path = path + "/" + video_incomplete_file;
|
||||
|
||||
if ( monitor->GetOptVideoWriter() != 0 ) {
|
||||
std::string container = monitor->OutputContainer();
|
||||
if ( container == "auto" || container == "" ) {
|
||||
container = "mp4";
|
||||
}
|
||||
if (monitor->GetOptVideoWriter() != 0) {
|
||||
/* Save as video */
|
||||
|
||||
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(
|
||||
video_file.c_str(),
|
||||
video_incomplete_path.c_str(),
|
||||
container.c_str(),
|
||||
monitor->GetVideoStream(),
|
||||
monitor->GetVideoCodecContext(),
|
||||
|
@ -213,20 +212,31 @@ Event::Event(
|
|||
zmDbDo(sql);
|
||||
}
|
||||
} else {
|
||||
sql = stringtf("UPDATE Events SET Videoed=1, DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
|
||||
zmDbDo(sql);
|
||||
std::string codec = videoStore->get_codec();
|
||||
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
|
||||
delete storage;
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
/* Close the video file */
|
||||
if ( videoStore != nullptr ) {
|
||||
if (videoStore != nullptr) {
|
||||
Debug(4, "Deleting video store");
|
||||
delete videoStore;
|
||||
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.
|
||||
|
@ -245,21 +255,23 @@ Event::~Event() {
|
|||
}
|
||||
|
||||
std::string sql = stringtf(
|
||||
"UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d 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),
|
||||
delta_time.count(),
|
||||
frames, alarm_frames,
|
||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||
video_file.c_str(), // defaults to ""
|
||||
id);
|
||||
|
||||
if (!zmDbDoUpdate(sql)) {
|
||||
// Name might have been changed during recording, so just do the update without changing the name.
|
||||
sql = stringtf(
|
||||
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d 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),
|
||||
delta_time.count(),
|
||||
frames, alarm_frames,
|
||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||
video_file.c_str(), // defaults to ""
|
||||
id);
|
||||
zmDbDoUpdate(sql);
|
||||
} // end if no changed rows due to Name change during recording
|
||||
|
@ -312,32 +324,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;
|
||||
}
|
||||
|
@ -479,7 +491,7 @@ void Event::AddFrame(Image *image,
|
|||
Debug(1, "Writing snapshot");
|
||||
WriteFrameImage(image, timestamp, snapshot_file.c_str());
|
||||
} 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
|
||||
|
@ -491,7 +503,7 @@ void Event::AddFrame(Image *image,
|
|||
Debug(1, "Writing alarm image");
|
||||
WriteFrameImage(image, timestamp, alarm_file.c_str());
|
||||
} 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)) {
|
||||
|
|
|
@ -84,8 +84,13 @@ class Event {
|
|||
std::string alarm_file;
|
||||
VideoStore *videoStore;
|
||||
|
||||
std::string video_name;
|
||||
std::string container;
|
||||
std::string codec;
|
||||
std::string video_file;
|
||||
std::string video_path;
|
||||
std::string video_incomplete_file;
|
||||
std::string video_incomplete_path;
|
||||
|
||||
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.
|
||||
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->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));
|
||||
|
|
|
@ -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) {
|
||||
if (!(outfile or open())) return false;
|
||||
// Going to write a brief header
|
||||
Debug(1, "Writing header ZM %lu %" PRId64, bytes, pts);
|
||||
if ( fprintf(outfile, "ZM %lu %" PRId64 "\n", bytes, pts) < 0 ) {
|
||||
Debug(1, "Writing header ZM %zu %" PRId64, bytes, pts);
|
||||
if (fprintf(outfile, "ZM %zu %" PRId64 "\n", bytes, pts) < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
Error("Problem during writing: %s", strerror(errno));
|
||||
} else {
|
||||
|
|
|
@ -270,7 +270,6 @@ int Image::PopulateFrame(AVFrame *frame) {
|
|||
frame->width = width;
|
||||
frame->height = height;
|
||||
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)");
|
||||
return 1;
|
||||
} // int Image::PopulateFrame(AVFrame *frame)
|
||||
|
|
|
@ -155,7 +155,7 @@ bool Monitor::MonitorLink::connect() {
|
|||
|
||||
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
|
||||
map_fd = open(mem_file.c_str(), O_RDWR, (mode_t)0600);
|
||||
if (map_fd < 0) {
|
||||
|
@ -182,14 +182,14 @@ bool Monitor::MonitorLink::connect() {
|
|||
disconnect();
|
||||
return false;
|
||||
} 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();
|
||||
return false;
|
||||
}
|
||||
|
||||
mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0);
|
||||
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();
|
||||
return false;
|
||||
}
|
||||
|
@ -947,7 +947,7 @@ bool Monitor::connect() {
|
|||
map_fd = -1;
|
||||
return false;
|
||||
} 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);
|
||||
map_fd = -1;
|
||||
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);
|
||||
if (mem_ptr == MAP_FAILED) {
|
||||
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
|
||||
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
|
||||
} 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
|
||||
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);
|
||||
map_fd = -1;
|
||||
mem_ptr = nullptr;
|
||||
|
@ -1656,7 +1656,7 @@ void Monitor::CheckAction() {
|
|||
}
|
||||
}
|
||||
|
||||
void Monitor::UpdateCaptureFPS() {
|
||||
void Monitor::UpdateFPS() {
|
||||
if ( fps_report_interval and
|
||||
(
|
||||
!(image_count%fps_report_interval)
|
||||
|
@ -1675,82 +1675,35 @@ void Monitor::UpdateCaptureFPS() {
|
|||
uint32 new_camera_bytes = camera->Bytes();
|
||||
uint32 new_capture_bandwidth =
|
||||
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",
|
||||
"Capturing",
|
||||
Debug(4, "FPS: capture count %d - last capture count %d = %d now:%lf, last %lf, elapsed %lf = capture: %lf fps analysis: %lf fps",
|
||||
image_count,
|
||||
last_capture_image_count,
|
||||
image_count - last_capture_image_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(),
|
||||
new_capture_fps);
|
||||
new_capture_fps,
|
||||
new_analysis_fps);
|
||||
|
||||
Info("%s: %d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec",
|
||||
name.c_str(), image_count, new_capture_fps, new_capture_bandwidth);
|
||||
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, new_analysis_fps);
|
||||
|
||||
shared_data->capture_fps = new_capture_fps;
|
||||
last_fps_time = now;
|
||||
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(
|
||||
"UPDATE LOW_PRIORITY Monitor_Status SET CaptureFPS = %.2lf, CaptureBandwidth=%u WHERE MonitorId=%u",
|
||||
new_capture_fps, new_capture_bandwidth, id);
|
||||
"UPDATE LOW_PRIORITY Monitor_Status SET CaptureFPS = %.2lf, CaptureBandwidth=%u, AnalysisFPS = %.2lf WHERE MonitorId=%u",
|
||||
new_capture_fps, new_capture_bandwidth, new_analysis_fps, id);
|
||||
dbQueue.push(std::move(sql));
|
||||
} // now != last_fps_time
|
||||
} // end if report fps
|
||||
} // void Monitor::UpdateCaptureFPS()
|
||||
|
||||
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
|
||||
} // void Monitor::UpdateFPS()
|
||||
|
||||
// Would be nice if this JUST did analysis
|
||||
// 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");
|
||||
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;
|
||||
|
@ -1927,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) {
|
||||
|
@ -1939,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,
|
||||
|
@ -1966,7 +1916,7 @@ bool Monitor::Analyse() {
|
|||
if (event) {
|
||||
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 == RECORD && event_close_mode == CLOSE_TIME)
|
||||
|| std::chrono::duration_cast<Seconds>(timestamp.time_since_epoch()) % section_length == Seconds(0))) {
|
||||
|
@ -1975,8 +1925,8 @@ bool Monitor::Analyse() {
|
|||
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>(GetVideoWriterStartTime().time_since_epoch()).count()),
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()),
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(event->StartTime().time_since_epoch()).count()),
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - event->StartTime()).count()),
|
||||
static_cast<int64>(Seconds(section_length).count()));
|
||||
closeEvent();
|
||||
} // end if section_length
|
||||
|
@ -2054,26 +2004,27 @@ 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()
|
||||
&& !event->AlarmFrames()
|
||||
&& event_close_mode == CLOSE_ALARM
|
||||
&& timestamp - GetVideoWriterStartTime() >= min_section_length
|
||||
&& (!pre_event_count || Event::PreAlarmCount() >= alarm_frame_count - 1)) {
|
||||
&& (event_close_mode == CLOSE_ALARM)
|
||||
&& ((timestamp - event->StartTime()) >= min_section_length)
|
||||
&& ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count - 1))) {
|
||||
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
|
||||
name.c_str(), image_count, event->Id());
|
||||
closeEvent();
|
||||
} 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
|
||||
Debug(3,
|
||||
"pre_alarm_count in event %d, event frames %d, alarm frames %d event length %" PRIi64 " >=? %" PRIi64 " min",
|
||||
Event::PreAlarmCount(),
|
||||
"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(), pre_event_count,
|
||||
event->Frames(),
|
||||
event->AlarmFrames(),
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()),
|
||||
static_cast<int64>(Seconds(min_section_length).count()));
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - event->StartTime()).count()),
|
||||
static_cast<int64>(Seconds(min_section_length).count()),
|
||||
(event_close_mode == CLOSE_ALARM));
|
||||
}
|
||||
if ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1)) {
|
||||
// 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);
|
||||
shared_data->state = state = ALERT;
|
||||
} else if (state == ALERT) {
|
||||
if (analysis_image_count - last_alarm_count > post_event_count
|
||||
&& timestamp - GetVideoWriterStartTime() >= min_section_length) {
|
||||
if (
|
||||
((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",
|
||||
name.c_str(), analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames());
|
||||
//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);
|
||||
} 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,
|
||||
|
@ -2208,18 +2162,15 @@ 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
|
||||
|
||||
// incremement pre alarm image count
|
||||
//have_pre_alarmed_frames ++;
|
||||
Event::AddPreAlarmFrame(snap->image, timestamp, score, nullptr);
|
||||
} else if (state == ALARM) {
|
||||
for (const Zone &zone : zones) {
|
||||
|
@ -2234,7 +2185,7 @@ bool Monitor::Analyse() {
|
|||
if (event) {
|
||||
if (noteSetMap.size() > 0)
|
||||
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,
|
||||
name.c_str(), analysis_image_count, event->Id(),
|
||||
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.
|
||||
shared_data->last_read_index = snap->image_index;
|
||||
analysis_image_count++;
|
||||
if (function == MODECT or function == MOCORD)
|
||||
UpdateAnalysisFPS();
|
||||
}
|
||||
packetqueue.increment_it(analysis_it);
|
||||
packetqueue.unlock(packet_lock);
|
||||
|
@ -2363,7 +2312,7 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
|||
while ( 1 ) {
|
||||
dest_ptr = link_id_str;
|
||||
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++;
|
||||
} else {
|
||||
break;
|
||||
|
@ -2585,7 +2534,6 @@ int Monitor::Capture() {
|
|||
|
||||
// Will only be queued if there are iterators allocated in the queue.
|
||||
packetqueue.queuePacket(packet);
|
||||
UpdateCaptureFPS();
|
||||
} else { // result == 0
|
||||
// Question is, do we update last_write_index etc?
|
||||
return 0;
|
||||
|
@ -2625,7 +2573,7 @@ bool Monitor::Decode() {
|
|||
//
|
||||
//capture_image = packet->image = new Image(width, height, camera->Colours(), camera->SubpixelOrder());
|
||||
int ret = packet->decode(camera->getVideoCodecContext());
|
||||
if (ret > 0) {
|
||||
if (ret > 0 and !zm_terminate) {
|
||||
if (packet->in_frame and !packet->image) {
|
||||
packet->image = new Image(camera_width, camera_height, camera->Colours(), camera->SubpixelOrder());
|
||||
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;
|
||||
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] ) {
|
||||
bool found_macro = false;
|
||||
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;
|
||||
Centiseconds centi_sec = std::chrono::duration_cast<Centiseconds>(
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public:
|
|||
} Deinterlace;
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN=-1,
|
||||
UNKNOWN,
|
||||
IDLE,
|
||||
PREALARM,
|
||||
ALARM,
|
||||
|
@ -546,8 +546,7 @@ public:
|
|||
unsigned int GetLastWriteIndex() const;
|
||||
uint64_t GetLastEventId() const;
|
||||
double GetFPS() const;
|
||||
void UpdateAnalysisFPS();
|
||||
void UpdateCaptureFPS();
|
||||
void UpdateFPS();
|
||||
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
|
||||
void ForceAlarmOff();
|
||||
void CancelForced();
|
||||
|
|
|
@ -229,6 +229,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
|
|||
break;
|
||||
case CMD_QUIT :
|
||||
Info("User initiated exit - CMD_QUIT");
|
||||
zm_terminate = true;
|
||||
break;
|
||||
case CMD_QUERY :
|
||||
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);
|
||||
|
||||
// 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)
|
||||
|
||||
bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint timestamp) {
|
||||
|
|
|
@ -209,7 +209,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
|||
--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 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)
|
||||
#endif
|
||||
{
|
||||
zm_terminate = true;
|
||||
Error("Got signal %d (%s), crashing", signal, strsignal(signal));
|
||||
#if (defined(__i386__) || defined(__x86_64__))
|
||||
// Get more information if available
|
||||
|
|
|
@ -619,7 +619,8 @@ VideoStore::~VideoStore() {
|
|||
|
||||
Debug(1, "Writing trailer");
|
||||
/* 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));
|
||||
} else {
|
||||
Debug(3, "Success Writing trailer");
|
||||
|
@ -629,7 +630,7 @@ VideoStore::~VideoStore() {
|
|||
if (!(out_format->flags & AVFMT_NOFILE)) {
|
||||
/* Close the out file. */
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -111,6 +111,13 @@ class VideoStore {
|
|||
int writePacket(const std::shared_ptr<ZMPacket> &pkt);
|
||||
int write_packets(PacketQueue &queue);
|
||||
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
|
||||
|
|
|
@ -268,7 +268,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
std::this_thread::sleep_for(sleep_time);
|
||||
}
|
||||
if (zm_terminate){
|
||||
if (zm_terminate) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -308,6 +308,7 @@ int main(int argc, char *argv[]) {
|
|||
result = -1;
|
||||
break;
|
||||
}
|
||||
monitors[i]->UpdateFPS();
|
||||
|
||||
// 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()
|
||||
|
|
|
@ -230,12 +230,11 @@ rm .gitignore
|
|||
cd ../
|
||||
|
||||
|
||||
if [ !-e "$DIRECTORY.orig.tar.gz" ]; then
|
||||
read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]"
|
||||
if [[ $REPLY == [yY] ]]; then
|
||||
|
||||
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
|
||||
fi;
|
||||
if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then
|
||||
read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]"
|
||||
if [[ "$REPLY" == "" || "$REPLY" == [yY] ]]; then
|
||||
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
|
||||
fi;
|
||||
fi;
|
||||
|
||||
IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
|
||||
|
|
|
@ -93,7 +93,7 @@ if ( canView('Events') or canView('Snapshots') ) {
|
|||
$exportFormat,
|
||||
$exportCompress,
|
||||
$exportStructure,
|
||||
(!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport'),
|
||||
(!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport')
|
||||
)) {
|
||||
ajaxResponse(array('exportFile'=>$exportFile));
|
||||
} else {
|
||||
|
|
|
@ -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;
|
||||
|
@ -239,15 +240,17 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
|
|||
} # 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;
|
||||
ZM\Debug('Calling the following sql query: ' .$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 {
|
||||
$filtered_rows = $unfiltered_rows;
|
||||
} # end if search_filter->terms() > 1
|
||||
|
||||
if ($limit)
|
||||
$filtered_rows = array_slice($filtered_rows, $offset, $limit);
|
||||
|
||||
$returned_rows = array();
|
||||
foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) {
|
||||
foreach ($filtered_rows as $row) {
|
||||
$event = new ZM\Event($row);
|
||||
|
||||
$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');
|
||||
|
||||
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>
|
||||
';
|
||||
|
|
|
@ -495,6 +495,10 @@ class Monitor extends ZM_Object {
|
|||
return $this->Server()->UrlToIndex($port);
|
||||
}
|
||||
|
||||
public function UrlToZMS($port=null) {
|
||||
return $this->Server()->UrlToZMS($port).'?mid='.$this->Id();
|
||||
}
|
||||
|
||||
public function sendControlCommand($command) {
|
||||
// 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) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@ function MonitorStream(monitorData) {
|
|||
this.id = monitorData.id;
|
||||
this.connKey = monitorData.connKey;
|
||||
this.url = monitorData.url;
|
||||
this.url_to_zms = monitorData.url_to_zms;
|
||||
this.width = monitorData.width;
|
||||
this.height = monitorData.height;
|
||||
this.scale = 100;
|
||||
this.status = null;
|
||||
this.alarmState = STATE_IDLE;
|
||||
this.lastAlarmState = STATE_IDLE;
|
||||
|
@ -15,19 +17,68 @@ function MonitorStream(monitorData) {
|
|||
};
|
||||
this.type = monitorData.type;
|
||||
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) {
|
||||
// Step 1 make sure we are streaming instead of a static image
|
||||
var stream = $j('#liveStream'+this.id);
|
||||
if (!stream.length) {
|
||||
console.log('No live stream');
|
||||
return;
|
||||
}
|
||||
stream = stream[0];
|
||||
if ( !stream ) {
|
||||
console.log('No live stream');
|
||||
return;
|
||||
}
|
||||
if ( !stream.src ) {
|
||||
const stream = this.getElement();
|
||||
if (!stream) return;
|
||||
|
||||
if (!stream.src) {
|
||||
// Website Monitors won't have an img tag
|
||||
console.log('No src for #liveStream'+this.id);
|
||||
console.log(stream);
|
||||
|
@ -38,7 +89,7 @@ function MonitorStream(monitorData) {
|
|||
src += '&connkey='+this.connKey;
|
||||
}
|
||||
if ( stream.src != src ) {
|
||||
console.log("Setting to streaming");
|
||||
console.log("Setting to streaming: " + src);
|
||||
stream.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="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(
|
||||
'js/tableExport.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
|
||||
var ratio = baseWidth / baseHeight;
|
||||
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);
|
||||
// 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);
|
||||
//console.log("bottomLoc: " + bottomEl.offset().top + " + (" + bottomEl.outerHeight(true) + ' - ' + bottomEl.outerHeight() +') + '+bottomEl.outerHeight(true));
|
||||
var newHeight = viewPort.height() - (bottomLoc - scaleEl.outerHeight(true));
|
||||
//console.log("newHeight = " + viewPort.height() +" - " + bottomLoc + ' - ' + scaleEl.outerHeight(true));
|
||||
var newWidth = ratio * newHeight;
|
||||
if (newWidth > container.innerWidth()) {
|
||||
newWidth = container.innerWidth();
|
||||
|
@ -598,13 +609,15 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) {
|
|||
return parseInt($j(this).val());
|
||||
}).get();
|
||||
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.
|
||||
if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) {
|
||||
closest = this.valueOf();
|
||||
}
|
||||
});
|
||||
autoScale = closest;
|
||||
if (closest) {
|
||||
autoScale = closest;
|
||||
}
|
||||
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 SCALE_BASE = <?php echo SCALE_BASE ?>;
|
||||
|
||||
var refreshParent = <?php
|
||||
if ( ! empty($refreshParent) ) {
|
||||
|
|
|
@ -300,7 +300,7 @@ function getCmdResponse(respObj, respText) {
|
|||
|
||||
if (streamStatus.auth) {
|
||||
// Try to reload the image stream.
|
||||
var streamImg = $j('#evtStream');
|
||||
var streamImg = document.getElementById('evtStream');
|
||||
if (streamImg) {
|
||||
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
|
||||
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});
|
||||
|
|
|
@ -317,5 +317,10 @@ function initPage() {
|
|||
}
|
||||
selectLayout('#zmMontageLayout');
|
||||
}
|
||||
|
||||
function watchFullscreen() {
|
||||
const content = document.getElementById('content');
|
||||
openFullscreen(content);
|
||||
}
|
||||
// Kick everything off
|
||||
$j(document).ready(initPage);
|
||||
|
|
|
@ -16,6 +16,9 @@ function generateVideoResponse( data, responseText ) {
|
|||
}
|
||||
|
||||
function generateVideo() {
|
||||
$j.ajaxSetup({
|
||||
timeout: 0
|
||||
});
|
||||
var form = $j('#videoForm').serialize();
|
||||
$j.getJSON(thisUrl + '?view=request&request=event&action=video', form)
|
||||
.done(generateVideoResponse)
|
||||
|
|
|
@ -970,5 +970,20 @@ function 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
|
||||
$j(document).ready(initPage);
|
||||
|
|
|
@ -97,9 +97,13 @@ foreach( dbFetchAll( 'SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, a
|
|||
$labels[$row['Preset']] = $row['Label'];
|
||||
}
|
||||
|
||||
foreach ( $labels as $index=>$label ) {
|
||||
foreach ($labels as $index=>$label) {
|
||||
?>
|
||||
labels[<?php echo validInt($index) ?>] = '<?php echo validJsStr($label) ?>';
|
||||
<?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
|
||||
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
|
||||
monitors[i].setScale('auto');
|
||||
monitors[i].start(delay);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ monitorData[monitorData.length] = {
|
|||
'width': <?php echo $monitor->ViewWidth() ?>,
|
||||
'height':<?php echo $monitor->ViewHeight() ?>,
|
||||
'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() ?>',
|
||||
'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
|
||||
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
|
||||
monitors[i].setScale('auto');
|
||||
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);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ monitorData[monitorData.length] = {
|
|||
'width': <?php echo $monitor->ViewWidth() ?>,
|
||||
'height':<?php echo $monitor->ViewHeight() ?>,
|
||||
'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() ?>',
|
||||
'refresh': '<?php echo $monitor->Refresh() ?>'
|
||||
};
|
||||
|
@ -24,7 +25,7 @@ var STATE_TAPE = <?php echo STATE_TAPE ?>;
|
|||
|
||||
var stateStrings = new Array();
|
||||
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_ALERT] = "<?php echo translate('Alert') ?>";
|
||||
stateStrings[STATE_TAPE] = "<?php echo translate('Record') ?>";
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -206,6 +206,9 @@ if ( canView('System') ) {
|
|||
<?php echo translate('Snapshot') ?>
|
||||
</button>
|
||||
<?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>
|
||||
</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">
|
||||
<i class="material-icons md-18">zoom_out</i>
|
||||
</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
|
||||
} // end if streamMode==jpeg
|
||||
?>
|
||||
|
|
|
@ -80,15 +80,14 @@ xhtmlHeaders(__FILE__, translate('Zones'));
|
|||
<?php echo getStreamHTML($monitor, $options); ?>
|
||||
<svg class="zones" viewBox="0 0 <?php echo $monitor->ViewWidth().' '.$monitor->ViewHeight() ?>">
|
||||
<?php
|
||||
foreach( array_reverse($zones) as $zone ) {
|
||||
foreach (array_reverse($zones) as $zone) {
|
||||
?>
|
||||
<polygon points="<?php echo $zone['AreaCoords'] ?>"
|
||||
class="zmlink <?php echo $zone['Type']?>"
|
||||
data-on-click-true="streamCmdQuit"
|
||||
data-url="?view=zone&mid=<?php echo $mid ?>&zid=<?php echo $zone['Id'] ?>"
|
||||
/>
|
||||
<?php
|
||||
} // end foreach zone
|
||||
} // end foreach zone
|
||||
?>
|
||||
Sorry, your browser does not support inline SVG
|
||||
</svg>
|
||||
|
@ -96,37 +95,37 @@ xhtmlHeaders(__FILE__, translate('Zones'));
|
|||
<?php echo translate('State') ?>: <span id="stateValue<?php echo $monitor->Id() ?>"></span> - <span id="fpsValue<?php echo $monitor->Id() ?>"></span> fps
|
||||
</div>
|
||||
</div>
|
||||
<div class="zones">
|
||||
<table id="zonesTable" class="major">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="colName"><?php echo translate('Name') ?></th>
|
||||
<th class="colType"><?php echo translate('Type') ?></th>
|
||||
<th class="colUnits"><?php echo translate('AreaUnits') ?></th>
|
||||
<th class="colMark"><?php echo translate('Mark') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach( $zones as $zone ) {
|
||||
?>
|
||||
<tr>
|
||||
<td class="colName"><?php echo makeLink('?view=zone&mid='.$mid.'&zid='.$zone['Id'], validHtmlStr($zone['Name']), true, 'data-on-click-true="streamCmdQuit"'); ?></td>
|
||||
<td class="colType"><?php echo validHtmlStr($zone['Type']) ?></td>
|
||||
<td class="colUnits"><?php echo $zone['Area'] ?> / <?php echo sprintf('%.2f', ($zone['Area']*100)/($monitor->ViewWidth()*$monitor->ViewHeight()) ) ?></td>
|
||||
<td class="colMark"><input type="checkbox" name="markZids[]" value="<?php echo $zone['Id'] ?>" data-on-click-this="configureDeleteButton"<?php if ( !canEdit('Monitors') ) { ?> disabled="disabled"<?php } ?>/></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="contentButtons">
|
||||
<?php echo makeButton('?view=zone&mid='.$mid.'&zid=0', 'AddNewZone', canEdit('Monitors')); ?>
|
||||
<button type="submit" name="deleteBtn" value="Delete" disabled="disabled"><?php echo translate('Delete') ?></button>
|
||||
</div>
|
||||
</div><!--zones-->
|
||||
<br class="clear"/>
|
||||
<div class="zones">
|
||||
<table id="zonesTable" class="major">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="colName"><?php echo translate('Name') ?></th>
|
||||
<th class="colType"><?php echo translate('Type') ?></th>
|
||||
<th class="colUnits"><?php echo translate('AreaUnits') ?></th>
|
||||
<th class="colMark"><?php echo translate('Mark') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach( $zones as $zone ) {
|
||||
?>
|
||||
<tr>
|
||||
<td class="colName"><?php echo makeLink('?view=zone&mid='.$mid.'&zid='.$zone['Id'], validHtmlStr($zone['Name']), true, 'data-on-click-true="streamCmdQuit"'); ?></td>
|
||||
<td class="colType"><?php echo validHtmlStr($zone['Type']) ?></td>
|
||||
<td class="colUnits"><?php echo $zone['Area'] ?> / <?php echo sprintf('%.2f', ($zone['Area']*100)/($monitor->ViewWidth()*$monitor->ViewHeight()) ) ?></td>
|
||||
<td class="colMark"><input type="checkbox" name="markZids[]" value="<?php echo $zone['Id'] ?>" data-on-click-this="configureDeleteButton"<?php if ( !canEdit('Monitors') ) { ?> disabled="disabled"<?php } ?>/></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="contentButtons">
|
||||
<?php echo makeButton('?view=zone&mid='.$mid.'&zid=0', 'AddNewZone', canEdit('Monitors')); ?>
|
||||
<button type="submit" name="deleteBtn" value="Delete" disabled="disabled"><?php echo translate('Delete') ?></button>
|
||||
</div>
|
||||
</div><!--zones-->
|
||||
<br class="clear"/>
|
||||
</div><!--Monitor-->
|
||||
<?php
|
||||
} # end foreach monitor
|
||||
|
|
Loading…
Reference in New Issue