Merge branch 'master' of github.com:ZoneMinder/zoneminder

This commit is contained in:
Isaac Connor 2021-11-29 18:50:52 -05:00
commit 2b289abb95
89 changed files with 1888 additions and 603 deletions

View File

@ -167,6 +167,8 @@ set(ZM_NO_X10 "OFF" CACHE BOOL
set(ZM_ONVIF "ON" CACHE BOOL
"Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not
work with all cameras claiming to be ONVIF compliant. default: ON")
set(ZM_NO_PCRE "OFF" CACHE BOOL
"Set to ON to skip libpcre3 checks and force building ZM without libpcre3. default: OFF")
set(ZM_NO_RTSPSERVER "OFF" CACHE BOOL
"Set to ON to skip building ZM with rtsp server support. default: OFF")
set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING
@ -407,21 +409,24 @@ else()
message(FATAL_ERROR "ZoneMinder requires pthread but it was not found on your system")
endif()
# pcre (using find_library and find_path)
find_library(PCRE_LIBRARIES pcre)
if(PCRE_LIBRARIES)
set(HAVE_LIBPCRE 1)
list(APPEND ZM_BIN_LIBS "${PCRE_LIBRARIES}")
find_path(PCRE_INCLUDE_DIR pcre.h)
if(PCRE_INCLUDE_DIR)
include_directories("${PCRE_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${PCRE_INCLUDE_DIR}")
# Do not check for cURL if ZM_NO_CURL is on
if(NOT ZM_NO_PRCE)
# pcre (using find_library and find_path)
find_library(PCRE_LIBRARIES pcre)
if(PCRE_LIBRARIES)
set(HAVE_LIBPCRE 1)
list(APPEND ZM_BIN_LIBS "${PCRE_LIBRARIES}")
find_path(PCRE_INCLUDE_DIR pcre.h)
if(PCRE_INCLUDE_DIR)
include_directories("${PCRE_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${PCRE_INCLUDE_DIR}")
endif()
mark_as_advanced(FORCE PCRE_LIBRARIES PCRE_INCLUDE_DIR)
check_include_file("pcre.h" HAVE_PCRE_H)
set(optlibsfound "${optlibsfound} PCRE")
else()
set(optlibsnotfound "${optlibsnotfound} PCRE")
endif()
mark_as_advanced(FORCE PCRE_LIBRARIES PCRE_INCLUDE_DIR)
check_include_file("pcre.h" HAVE_PCRE_H)
set(optlibsfound "${optlibsfound} PCRE")
else()
set(optlibsnotfound "${optlibsnotfound} PCRE")
endif()
# mysqlclient (using find_library and find_path)
@ -540,6 +545,7 @@ set(ZM_PCRE 0)
if(HAVE_LIBPCRE AND HAVE_PCRE_H)
set(ZM_PCRE 1)
endif()
# Check for mmap and enable in all components
set(ZM_MEM_MAPPED 0)
set(ENABLE_MMAP no)

View File

@ -4,6 +4,7 @@
configure_file(zm_create.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" @ONLY)
configure_file(zm_update-1.31.30.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" @ONLY)
configure_file(zm_update-1.35.24.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.35.24.sql" @ONLY)
configure_file(zm_update-1.37.4.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.37.4.sql" @ONLY)
# Glob all database upgrade scripts
file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql")
@ -15,6 +16,8 @@ install(FILES ${dbfileslist} DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
# install zm_update-1.35.24.sql
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.35.24.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
# install zm_update-1.37.4.sql
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.37.4.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
# install zm_create.sql
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
@ -22,3 +25,8 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_I
# install triggers.sql
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
# install manufacturers.sql
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/manufacturers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
# install models.sql
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/models.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")

24
db/manufacturers.sql Normal file
View File

@ -0,0 +1,24 @@
INSERT IGNORE INTO Manufacturers VALUES (1, 'Acti');
INSERT IGNORE INTO Manufacturers VALUES (2, 'Amcrest');
INSERT IGNORE INTO Manufacturers VALUES (3, 'Airlink101');
INSERT IGNORE INTO Manufacturers VALUES (4, 'Arecont Vision');
INSERT IGNORE INTO Manufacturers VALUES (5, 'Axis');
INSERT IGNORE INTO Manufacturers VALUES (6, 'Dahua');
INSERT IGNORE INTO Manufacturers VALUES (7, 'D-Link');
INSERT IGNORE INTO Manufacturers VALUES (8, 'Edimax');
INSERT IGNORE INTO Manufacturers VALUES (9, 'Foscam');
INSERT IGNORE INTO Manufacturers VALUES (10, 'Gadspot');
INSERT IGNORE INTO Manufacturers VALUES (11, 'GrandStream');
INSERT IGNORE INTO Manufacturers VALUES (12, 'HikVision');
INSERT IGNORE INTO Manufacturers VALUES (13, 'JVC');
INSERT IGNORE INTO Manufacturers VALUES (14, 'Maginon');
INSERT IGNORE INTO Manufacturers VALUES (15, 'Mobotix');
INSERT IGNORE INTO Manufacturers VALUES (16, 'Oncam Grandeye');
INSERT IGNORE INTO Manufacturers VALUES (17, 'Panasonic');
INSERT IGNORE INTO Manufacturers VALUES (18, 'Pelco');
INSERT IGNORE INTO Manufacturers VALUES (19, 'Sony');
INSERT IGNORE INTO Manufacturers VALUES (20, 'TP-Link');
INSERT IGNORE INTO Manufacturers VALUES (21, 'Trendnet');
INSERT IGNORE INTO Manufacturers VALUES (22, 'VisionTek');
INSERT IGNORE INTO Manufacturers VALUES (23, 'Vivotek');
INSERT IGNORE INTO Manufacturers VALUES (24, 'Wansview');

56
db/models.sql Normal file
View File

@ -0,0 +1,56 @@
/* INSERT INTO Manufacturers VALUES (1, 'Acti'); */
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A21');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A23');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A24');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A28');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A31');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A310');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A311');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A32');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A41');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A415');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A416');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A418');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A42');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A421');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A43');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A45');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A46');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A48');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (1, 'A74');
/*
INSERT INTO Manufacturers VALUES (2, 'Amcrest');
*/
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (2, 'IP8M-T2499EW');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (2, 'ASH42-B');
/*
INSERT INTO Manufacturers VALUES (3, 'Airlink101');
INSERT INTO Manufacturers VALUES (4, 'Arecont Vision');
INSERT INTO Manufacturers VALUES (5, 'Axis');
INSERT INTO Manufacturers VALUES (6, 'Dahua');
INSERT INTO Manufacturers VALUES (7, 'D-Link');
*/
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (7, 'DCS-930L');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (7, 'DCS-932L');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (7, 'DCS-933L');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (7, 'DCS-942L');
INSERT IGNORE INTO Models (ManufacturerId,Name) VALUES (7, 'DCS-5020L');
/*
INSERT INTO Manufacturers VALUES (8, 'Edimax');
INSERT INTO Manufacturers VALUES (9, 'Foscam');
INSERT INTO Manufacturers VALUES (10, 'Gadspot');
INSERT INTO Manufacturers VALUES (11, 'GrandStream');
INSERT INTO Manufacturers VALUES (12, 'HikVision');
INSERT INTO Manufacturers VALUES (13, 'JVC');
INSERT INTO Manufacturers VALUES (14, 'Maginon');
INSERT INTO Manufacturers VALUES (15, 'Mobotix');
INSERT INTO Manufacturers VALUES (16, 'Oncam Grandeye');
INSERT INTO Manufacturers VALUES (17, 'Panasonic');
INSERT INTO Manufacturers VALUES (18, 'Pelco');
INSERT INTO Manufacturers VALUES (19, 'Sony');
INSERT INTO Manufacturers VALUES (20, 'TP-Link');
INSERT INTO Manufacturers VALUES (21, 'Trendnet');
INSERT INTO Manufacturers VALUES (22, 'VisionTek');
INSERT INTO Manufacturers VALUES (23, 'Vivotek');
INSERT INTO Manufacturers VALUES (24, 'Wansview');
*/

View File

@ -412,6 +412,7 @@ CREATE TABLE `Models` (
DROP TABLE IF EXISTS `MonitorPresets`;
CREATE TABLE `MonitorPresets` (
`Id` int(10) unsigned NOT NULL auto_increment,
`ModelId` int unsigned, FOREIGN KEY (`ModelId`) REFERENCES `Models` (Id),
`Name` varchar(64) NOT NULL default '',
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket','VNC') NOT NULL default 'Local',
`Device` tinytext,
@ -447,12 +448,16 @@ CREATE TABLE `Monitors` (
`Notes` TEXT,
`ServerId` int(10) unsigned,
`StorageId` smallint(5) unsigned default 0,
`ManufacturerId` int unsigned, FOREIGN KEY (`ManufacturerId`) REFERENCES `Manufacturers` (Id),
`ModelId` int unsigned, FOREIGN KEY (`ModelId`) REFERENCES `Models` (Id),
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket','VNC') NOT NULL default 'Local',
`Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor',
`Enabled` tinyint(3) unsigned NOT NULL default '1',
`DecodingEnabled` tinyint(3) unsigned NOT NULL default '1',
`LinkedMonitors` varchar(255),
`Triggers` set('X10') NOT NULL default '',
`EventStartCommand` VARCHAR(255) NOT NULL DEFAULT '',
`EventEndCommand` VARCHAR(255) NOT NULL DEFAULT '',
`ONVIF_URL` VARCHAR(255) NOT NULL DEFAULT '',
`ONVIF_Username` VARCHAR(64) NOT NULL DEFAULT '',
`ONVIF_Password` VARCHAR(64) NOT NULL DEFAULT '',
@ -971,81 +976,81 @@ INSERT INTO `Controls` VALUES (NULL,'Amcrest HTTP API','Ffmpeg','Amcrest_HTTP',0
-- Add some monitor preset values
--
INSERT into MonitorPresets VALUES (NULL,'Amcrest, IP8M-T2499EW 640x480, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp','NULL',554,'rtsp://<username>:<password>@<ip-address>/cam/realmonitor?channel=1&subtype=1',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'Amcrest, IP8M-T2499EW 3840x2160, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp','NULL',554,'rtsp://<username>:<password>@<ip-address>/cam/realmonitor?channel=1&subtype=0',NULL,3840,2160,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, B&W','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&color=0',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg, B&W','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&color=0',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, unicast','Remote','rtsp',0,255,'rtsp','rtpUni','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, multicast','Remote','rtsp',0,255,'rtsp','rtpMulti','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, RTP/RTSP','Remote','rtsp',0,255,'rtsp','rtpRtsp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, RTP/RTSP/HTTP','Remote',NULL,NULL,NULL,'rtsp','rtpRtspHttp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'D-link DCS-930L, 640x480, mjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/mjpeg.cgi',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'D-Link DCS-5020L, 640x480, mjpeg','Remote','http',0,0,'http','simple','<username>:<pwd>@<ip-address>','80','/video.cgi',NULL,640,480,0,NULL,1,'34',NULL,'<username>:<pwd>@<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/GetData.cgi',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'IP Webcam by Pavel Khlebovich 1920x1080','Remote','/dev/video<?>','0',255,'http','simple','<ip-address>','8080','/video','',1920,1080,0,NULL,0,'0','','',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'VEO Observer, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Blue Net Video Server, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/cgi-bin/image.cgi?control=0&id=admin&passwd=admin',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'ACTi IP, mpeg4, unicast','Remote',NULL,NULL,NULL,'rtsp','rtpUni','<ip-address>',7070,'','/track',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>/axis-media/media.amp?videocodec=h264',NULL,NULL,NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Vivotek FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>:554/live.sdp',NULL,NULL,NULL,352,240,NULL,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>/axis-media/media.amp',NULL,NULL,NULL,640,480,NULL,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'ACTi TCM FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://admin:123456@<host/address>:7070',NULL,NULL,NULL,320,240,NULL,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 320x240','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 320x240, max 5 FPS','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 640x480','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 640x480, max 5 FPS','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 320x240','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 640x480','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 320x240','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 320x240, max 5 FPS','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 640x480','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 640x480, max 5 FPS','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 320x240','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 640x480','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Remote ZoneMinder','Remote',NULL,NULL,NULL,'http','simple','<ip-address>',80,'/cgi-bin/nph-zms?mode=jpeg&monitor=<monitor-id>&scale=100&maxfps=5&buffer=0',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI8620 FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:554/11',NULL,704,576,0,NULL,1,'10','<admin_pwd>','<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI8608W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:554/11',NULL,640,480,0,NULL,1,'11','<admin_pwd>','<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI9821W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:88/videoMain',NULL,1280,720,0,NULL,1,'12','<admin_pwd>','<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Loftek Sentinel PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'<ip-address>','80','/videostream.cgi?user=<username>&pwd=<password>&resolution=32&rate=11',NULL,640,480,4,NULL,1,'13','','<username>:<pwd>@<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Airlink 777W PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'<username>:<password>@<ip-address>','80','/cgi/mjpg/mjpg.cgi',NULL,640,480,4,NULL,1,'7','','<username>:<pwd>@<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,'SunEyes SP-P1802SWPTZ','Libvlc','/dev/video<?>','0',255,'','rtpMulti','','80','rtsp://<ip-address>:554/11','',1920,1080,0,0.00,1,'16','-speed=64','<ip-address>:<port>',100,33);
INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1280x720, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1280,720,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1920x1080, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1920,1080,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,NULL,'Amcrest, IP8M-T2499EW 640x480, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp','NULL',554,'rtsp://<username>:<password>@<ip-address>/cam/realmonitor?channel=1&subtype=1',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,NULL,'Amcrest, IP8M-T2499EW 3840x2160, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp','NULL',554,'rtsp://<username>:<password>@<ip-address>/cam/realmonitor?channel=1&subtype=0',NULL,3840,2160,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 320x240, mpjpeg, B&W','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&color=0',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP, 640x480, mpjpeg, B&W','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&color=0',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
INSERT into MonitorPresets VALUES (NULL,NULL,'Axis IP, mpeg4, unicast','Remote','rtsp',0,255,'rtsp','rtpUni','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,NULL,'Axis IP, mpeg4, multicast','Remote','rtsp',0,255,'rtsp','rtpMulti','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,NULL,'Axis IP, mpeg4, RTP/RTSP','Remote','rtsp',0,255,'rtsp','rtpRtsp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,NULL,'Axis IP, mpeg4, RTP/RTSP/HTTP','Remote',NULL,NULL,NULL,'rtsp','rtpRtspHttp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'D-link DCS-930L, 640x480, mjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/mjpeg.cgi',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'D-Link DCS-5020L, 640x480, mjpeg','Remote','http',0,0,'http','simple','<username>:<pwd>@<ip-address>','80','/video.cgi',NULL,640,480,0,NULL,1,'34',NULL,'<username>:<pwd>@<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Gadspot IP, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Gadspot IP, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Gadspot IP, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/GetData.cgi',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Gadspot IP, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'IP Webcam by Pavel Khlebovich 1920x1080','Remote','/dev/video<?>','0',255,'http','simple','<ip-address>','8080','/video','',1920,1080,0,NULL,0,'0','','',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'VEO Observer, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Blue Net Video Server, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/cgi-bin/image.cgi?control=0&id=admin&passwd=admin',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,NULL,'ACTi IP, mpeg4, unicast','Remote',NULL,NULL,NULL,'rtsp','rtpUni','<ip-address>',7070,'','/track',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>/axis-media/media.amp?videocodec=h264',NULL,NULL,NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Vivotek FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>:554/live.sdp',NULL,NULL,NULL,352,240,NULL,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>/axis-media/media.amp',NULL,NULL,NULL,640,480,NULL,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'ACTi TCM FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://admin:123456@<host/address>:7070',NULL,NULL,NULL,320,240,NULL,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), PAL, 320x240','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), PAL, 320x240, max 5 FPS','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), PAL, 640x480','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), PAL, 640x480, max 5 FPS','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), NTSC, 320x240','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), NTSC, 640x480','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L2), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), PAL, 320x240','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), PAL, 320x240, max 5 FPS','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), PAL, 640x480','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), PAL, 640x480, max 5 FPS','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), NTSC, 320x240','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), NTSC, 640x480','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'BTTV Video (V4L1), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Remote ZoneMinder','Remote',NULL,NULL,NULL,'http','simple','<ip-address>',80,'/cgi-bin/nph-zms?mode=jpeg&monitor=<monitor-id>&scale=100&maxfps=5&buffer=0',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Foscam FI8620 FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:554/11',NULL,704,576,0,NULL,1,'10','<admin_pwd>','<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Foscam FI8608W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:554/11',NULL,640,480,0,NULL,1,'11','<admin_pwd>','<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Foscam FI9821W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:88/videoMain',NULL,1280,720,0,NULL,1,'12','<admin_pwd>','<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Loftek Sentinel PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'<ip-address>','80','/videostream.cgi?user=<username>&pwd=<password>&resolution=32&rate=11',NULL,640,480,4,NULL,1,'13','','<username>:<pwd>@<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Airlink 777W PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'<username>:<password>@<ip-address>','80','/cgi/mjpg/mjpg.cgi',NULL,640,480,4,NULL,1,'7','','<username>:<pwd>@<ip-address>',100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'SunEyes SP-P1802SWPTZ','Libvlc','/dev/video<?>','0',255,'','rtpMulti','','80','rtsp://<ip-address>:554/11','',1920,1080,0,0.00,1,'16','-speed=64','<ip-address>:<port>',100,33);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Qihan IP, 1280x720, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1280,720,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,NULL,'Qihan IP, 1920x1080, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1920,1080,3,NULL,0,NULL,NULL,NULL,100,100);
--
-- Add some zone preset values
@ -1115,6 +1120,9 @@ CREATE TABLE Snapshot_Events (
-- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts.
source @PKGDATADIR@/db/triggers.sql
source @PKGDATADIR@/db/manufacturers.sql
source @PKGDATADIR@/db/models.sql
--
-- Apply the initial configuration
--

47
db/zm_update-1.35.29.sql Normal file
View File

@ -0,0 +1,47 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ManufacturerId'
) > 0,
"SELECT 'Column ManufacturerId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `ManufacturerId` int(10) unsigned AFTER `StorageId`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ManufacturerId'
) > 0,
"SELECT 'FOREIGN KEY for ManufacturerId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD FOREIGN KEY (`ManufacturerId`) REFERENCES `Manufacturers` (Id)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ModelId'
) > 0,
"SELECT 'Column ModelId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `ModelId` int(10) unsigned AFTER `ManufacturerId`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ModelId'
) > 0,
"SELECT 'FOREIGN KEY for ModelId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD FOREIGN KEY (`ModelId`) REFERENCES `Models` (Id)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

73
db/zm_update-1.37.3.sql Normal file
View File

@ -0,0 +1,73 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ManufacturerId'
) > 0,
"SELECT 'Column ManufacturerId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `ManufacturerId` int(10) unsigned AFTER `StorageId`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ManufacturerId'
) > 0,
"SELECT 'FOREIGN KEY for ManufacturerId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD FOREIGN KEY (`ManufacturerId`) REFERENCES `Manufacturers` (Id)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ModelId'
) > 0,
"SELECT 'Column ModelId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `ModelId` int(10) unsigned AFTER `ManufacturerId`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'ModelId'
) > 0,
"SELECT 'FOREIGN KEY for ModelId already exists in Monitors'",
"ALTER TABLE `Monitors` ADD FOREIGN KEY (`ModelId`) REFERENCES `Models` (Id)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'MonitorPresets'
AND column_name = 'ModelId'
) > 0,
"SELECT 'Column ModelId already exists in MonitorPresets'",
"ALTER TABLE `MonitorPresets` ADD `ModelId` int(10) unsigned AFTER `Id`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE table_schema = DATABASE()
AND table_name = 'MonitorPresets'
AND column_name = 'ModelId'
) > 0,
"SELECT 'FOREIGN KEY for ModelId already exists in MonitorPresets'",
"ALTER TABLE `MonitorPresets` ADD FOREIGN KEY (`ModelId`) REFERENCES `Models` (Id)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
UPDATE `MonitorPresets` SET `ModelId`=(SELECT `Id` FROM `Models` WHERE `Name`='IP8M-T2499EW') WHERE `Name` like 'Amcrest, IP8M-T2499EW
%';

View File

@ -0,0 +1,2 @@
source @PKGDATADIR@/db/manufacturers.sql
source @PKGDATADIR@/db/models.sql

31
db/zm_update-1.37.5.sql Normal file
View File

@ -0,0 +1,31 @@
--
-- This update adds EventStartCommand and EventEndCommand
--
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Monitors'
AND table_schema = DATABASE()
AND column_name = 'EventEndCommand'
) > 0,
"SELECT 'Column EventEndCommand already exists in Monitors'",
"ALTER TABLE `Monitors` ADD COLUMN `EventEndCommand` VARCHAR(255) NOT NULL DEFAULT '' AFTER `Triggers`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Monitors'
AND table_schema = DATABASE()
AND column_name = 'EventStartCommand'
) > 0,
"SELECT 'Column EventStartCommand already exists in Monitors'",
"ALTER TABLE `Monitors` ADD COLUMN `EventStartCommand` VARCHAR(255) NOT NULL DEFAULT '' AFTER `Triggers`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -36,7 +36,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.37.1
Version: 1.37.5
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons

View File

@ -16,7 +16,6 @@ Build-Depends: debhelper (>= 11), sphinx-doc, python3-sphinx, dh-linktree, dh-ap
,libjpeg-turbo8-dev | libjpeg62-turbo-dev | libjpeg8-dev | libjpeg9-dev
,libturbojpeg0-dev
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
,libpcre3-dev
,libpolkit-gobject-1-dev
,libv4l-dev [!hurd-any]
,libvlc-dev
@ -70,7 +69,6 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,policykit-1
,rsyslog | system-log-daemon
,zip
,libpcre3
,libcrypt-eksblowfish-perl
,libdata-entropy-perl
,libvncclient1|libvncclient0

View File

@ -19,6 +19,7 @@ override_dh_auto_configure:
-DCMAKE_VERBOSE_MAKEFILE=ON \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_MAN=0 \
-DZM_NO_PCRE=ON \
-DZM_CONFIG_DIR="/etc/zm" \
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
-DZM_RUNDIR="/run/zm" \

View File

@ -4,7 +4,7 @@ Debian
.. contents::
Easy Way: Debian 11 (Bullseye)
------------------------
------------------------------
This procedure will guide you through the installation of ZoneMinder on Debian 11 (Bullseye).
@ -104,7 +104,7 @@ Add the following to the /etc/apt/sources.list.d/zoneminder.list file
You can do this using:
.. code-block::
::
echo "deb https://zmrepo.zoneminder.com/debian/release-1.36 buster/" | sudo tee /etc/apt/sources.list.d/zoneminder.list

View File

@ -43,6 +43,7 @@ require Date::Parse;
require POSIX;
use Date::Format qw(time2str);
use Time::HiRes qw(gettimeofday tv_interval stat);
use Scalar::Util qw(looks_like_number);
#our @ISA = qw(ZoneMinder::Object);
use parent qw(ZoneMinder::Object);
@ -601,7 +602,7 @@ sub CopyTo {
# First determine if we can move it to the dest.
# We do this before bothering to lock the event
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
if ( ! $$NewStorage{Id} ) {
if ( ! looks_like_number($$NewStorage{Id}) ) {
return 'New storage does not have an id. Moving will not happen.';
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
return 'Event is already located at ' . $NewPath;
@ -733,19 +734,22 @@ sub MoveTo {
my $was_in_transaction = !$ZoneMinder::Database::dbh->{AutoCommit};
$ZoneMinder::Database::dbh->begin_work() if !$was_in_transaction;
$self->lock_and_load(); # The fact that we are in a transaction might not imply locking
if (!$self->lock_and_load()) {
Warning('Unable to lock event record '.$$self{Id}); # The fact that we are in a transaction might not imply locking
$ZoneMinder::Database::dbh->commit() if !$was_in_transaction;
return 'Unable to lock event record';
}
my $OldStorage = $self->Storage(undef);
my $error = $self->CopyTo($NewStorage);
return $error if $error;
if (!$error) {
# Succeeded in copying all files, so we may now update the Event.
$$self{StorageId} = $$NewStorage{Id};
$self->Storage($NewStorage);
$error .= $self->save();
# Succeeded in copying all files, so we may now update the Event.
$$self{StorageId} = $$NewStorage{Id};
$self->Storage($NewStorage);
$error .= $self->save();
# Going to leave it to upper layer as to whether we rollback or not
# Going to leave it to upper layer as to whether we rollback or not
}
$ZoneMinder::Database::dbh->commit() if !$was_in_transaction;
return $error if $error;

View File

@ -230,8 +230,8 @@ sub Sql {
# PostCondition, so no further SQL
} else {
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
# Empty value will result in () from split
foreach my $temp_value ( $stripped_value ? split( /["'\s]*?,["'\s]*?/, $stripped_value ) : $stripped_value ) {
if ( $term->{attr} eq 'AlarmedZoneId' ) {
$value = '(SELECT * FROM Stats WHERE EventId=E.Id AND Score > 0 AND ZoneId='.$value.')';
} elsif ( $term->{attr} =~ /^MonitorName/ ) {
@ -250,7 +250,8 @@ sub Sql {
$$self{Server} = new ZoneMinder::Server($temp_value);
}
} elsif ( $term->{attr} eq 'StorageId' ) {
$value = "'$temp_value'";
# Empty means NULL, otherwise must be an integer
$value = $temp_value ne '' ? int($temp_value) : 'NULL';
$$self{Storage} = new ZoneMinder::Storage($temp_value);
} elsif ( $term->{attr} eq 'Name'
|| $term->{attr} eq 'Cause'

View File

@ -326,18 +326,30 @@ sub resumeMotionDetection {
sub Control {
my $self = shift;
if ( ! exists $$self{Control}) {
require ZoneMinder::Control;
my $Control = ZoneMinder::Control->find_one(Id=>$$self{ControlId});
if ($Control) {
require Module::Load::Conditional;
if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$$Control{Protocol} => undef})) {
Error("Can't load ZoneMinder::Control::$$Control{Protocol}\n$Module::Load::Conditional::ERROR");
return undef;
if (!exists $$self{Control}) {
if ($$self{ControlId}) {
require ZoneMinder::Control;
my $Control = ZoneMinder::Control->find_one(Id=>$$self{ControlId});
if ($Control) {
my $Protocol = $$Control{Protocol};
if (!$Protocol) {
Error("No protocol set in control $$Control{Id}, trying Name $$Control{Name}");
$Protocol = $$Control{Name};
}
require Module::Load::Conditional;
if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$Protocol => undef})) {
Error("Can't load ZoneMinder::Control::$Protocol\n$Module::Load::Conditional::ERROR");
return undef;
}
bless $Control, 'ZoneMinder::Control::'.$Protocol;
$$Control{MonitorId} = $$self{Id};
$$self{Control} = $Control;
} else {
Error("Unable to load control for control $$self{ControlId} for monitor $$self{Id}");
}
bless $Control, 'ZoneMinder::Control::'.$$Control{Protocol};
$$Control{MonitorId} = $$self{Id};
$$self{Control} = $Control;
} else {
Info("No ControlId set in monitor $$self{Id}")
}
}
return $$self{Control};

View File

@ -429,10 +429,20 @@ sub start {
# It's not running, or at least it's not been started by us
$process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef };
} elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) {
dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at "
if ($process->{term_sent_at}) {
dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' was told to term at "
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{term_sent_at}))
.", pid = $process->{pid}\n"
);
$process->{keepalive} = !undef;
$process->{delay} = 0;
delete $terminating_processes{$command};
} else {
dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at "
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
.", pid = $process->{pid}\n"
);
);
}
return;
}
@ -523,7 +533,7 @@ sub send_stop {
."\n"
);
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
return();
return ();
}
my $pid = $process->{pid};
@ -586,7 +596,7 @@ sub check_for_processes_to_kill {
sub stop {
my ( $daemon, @args ) = @_;
my $command = join(' ', $daemon, @args );
my $command = join(' ', $daemon, @args);
my $process = $cmd_hash{$command};
if ( !$process ) {
dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'");

View File

@ -263,7 +263,10 @@ sub countQuery {
sub getMonitorRef {
my $dbh = shift;
my $sql = 'SELECT `Id`,`Name`,`Type`,`Function`,`Width`,`Height`,`Colours`,`MaxFPS`,`AlarmMaxFPS` FROM `Monitors`';
my $sql = 'SELECT `Id`,`Name`,`Type`,`Function`,`Width`,`Height`,`Colours`,`MaxFPS`,`AlarmMaxFPS`,
(SELECT Name FROM Manufacturers WHERE Manufacturers.Id = ManufacturerId),
(SELECT Name FROM Models WHERE Models.Id = ModelId)
FROM `Monitors`';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({});

View File

@ -251,11 +251,11 @@ void zmDbQueue::process() {
mCondition.wait(lock);
}
while (!mQueue.empty()) {
if (mQueue.size() > 10) {
if (mQueue.size() > 20) {
Logger *log = Logger::fetch();
Logger::Level db_level = log->databaseLevel();
log->databaseLevel(Logger::NOLOG);
Warning("db queue size has grown larger %zu than 10 entries", mQueue.size());
Warning("db queue size has grown larger %zu than 20 entries", mQueue.size());
log->databaseLevel(db_level);
}
std::string sql = mQueue.front();
@ -271,8 +271,10 @@ void zmDbQueue::process() {
void zmDbQueue::push(std::string &&sql) {
if (mTerminate) return;
std::unique_lock<std::mutex> lock(mMutex);
mQueue.push(std::move(sql));
{
std::unique_lock<std::mutex> lock(mMutex);
mQueue.push(std::move(sql));
}
mCondition.notify_all();
}

View File

@ -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,27 @@ 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());
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 +155,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 +175,7 @@ Event::Event(
result = nullptr;
}
}
if ( !storage ) {
if (!storage) {
storage = new Storage();
Warning("Failed to find a storage area to save events.");
}
@ -178,24 +184,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 +211,32 @@ 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
if (storage != monitor->getStorage())
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 &noteSet = 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;
}
@ -534,7 +546,7 @@ void Event::AddFrame(Image *image,
or
(frame_type == BULK)
or
(fps and (frame_data.size() > fps))) {
(fps and (frame_data.size() > 5*fps))) {
Debug(1, "Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK(%d)",
frame_data.size(), write_to_db, fps, (frame_type == BULK));
WriteDbFrames();

View File

@ -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;

View File

@ -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));

View File

@ -458,6 +458,17 @@ int FfmpegCamera::OpenFfmpeg() {
#endif
} // end if hwaccel_name
// set codec to automatically determine how many threads suits best for the decoding job
mVideoCodecContext->thread_count = 0;
if (mVideoCodec->capabilities | AV_CODEC_CAP_FRAME_THREADS) {
mVideoCodecContext->thread_type = FF_THREAD_FRAME;
} else if (mVideoCodec->capabilities | AV_CODEC_CAP_SLICE_THREADS) {
mVideoCodecContext->thread_type = FF_THREAD_SLICE;
} else {
mVideoCodecContext->thread_count = 1; //don't use multithreading
}
ret = avcodec_open2(mVideoCodecContext, mVideoCodec, &opts);
e = nullptr;

View File

@ -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 {

View File

@ -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)

View File

@ -23,7 +23,7 @@ void bind_libvnc_symbols() {
libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL);
if (!libvnc_lib) {
Error("Error loading libvncclient: %s", dlerror());
Error("Error loading libvncclient.so: %s", dlerror());
return;
}
@ -135,11 +135,6 @@ VncCamera::VncCamera(
}
VncCamera::~VncCamera() {
if (capture and mRfb) {
if (mRfb->frameBuffer)
free(mRfb->frameBuffer);
(*rfbClientCleanup_f)(mRfb);
}
if (libvnc_lib) {
dlclose(libvnc_lib);
libvnc_lib = nullptr;
@ -253,6 +248,12 @@ int VncCamera::PostCapture() {
}
int VncCamera::Close() {
if (capture and mRfb) {
if (mRfb->frameBuffer)
free(mRfb->frameBuffer);
(*rfbClientCleanup_f)(mRfb);
mRfb = nullptr;
}
return 1;
}
#endif

View File

@ -43,11 +43,11 @@ Logger::IntMap Logger::smSyslogPriorities;
void Logger::usrHandler(int sig) {
Logger *logger = fetch();
if ( sig == SIGUSR1 )
if (sig == SIGUSR1)
logger->level(logger->level()+1);
else if ( sig == SIGUSR2 )
else if (sig == SIGUSR2)
logger->level(logger->level()-1);
Info("Logger - Level changed to %d", logger->level());
Info("Logger - Level changed to %d %s", logger->level(), smCodes[logger->level()].c_str());
}
Logger::Logger() :
@ -296,23 +296,23 @@ const std::string &Logger::id(const std::string &id) {
}
Logger::Level Logger::level(Logger::Level level) {
if ( level > NOOPT ) {
if (level > NOOPT) {
mLevel = limit(level);
mEffectiveLevel = NOLOG;
if ( mTerminalLevel > mEffectiveLevel )
if (mTerminalLevel > mEffectiveLevel)
mEffectiveLevel = mTerminalLevel;
if ( mDatabaseLevel > mEffectiveLevel )
if (mDatabaseLevel > mEffectiveLevel)
mEffectiveLevel = mDatabaseLevel;
if ( mFileLevel > mEffectiveLevel )
if (mFileLevel > mEffectiveLevel)
mEffectiveLevel = mFileLevel;
if ( mSyslogLevel > mEffectiveLevel )
if (mSyslogLevel > mEffectiveLevel)
mEffectiveLevel = mSyslogLevel;
if ( mEffectiveLevel > mLevel)
if (mEffectiveLevel > mLevel)
mEffectiveLevel = mLevel;
// DEBUG levels should flush
if ( mLevel > INFO )
if (mLevel > INFO)
mFlush = true;
}
return mLevel;

View File

@ -70,7 +70,7 @@
// It will be used whereever a Monitor dbrow is needed. WHERE conditions can be appended
std::string load_monitor_sql =
"SELECT `Id`, `Name`, `ServerId`, `StorageId`, `Type`, `Function`+0, `Enabled`, `DecodingEnabled`, "
"`LinkedMonitors`, `AnalysisFPSLimit`, `AnalysisUpdateDelay`, `MaxFPS`, `AlarmMaxFPS`,"
"`LinkedMonitors`, `EventStartCommand`, `EventEndCommand`, `AnalysisFPSLimit`, `AnalysisUpdateDelay`, `MaxFPS`, `AlarmMaxFPS`,"
"`Device`, `Channel`, `Format`, `V4LMultiBuffer`, `V4LCapturesPerFrame`, " // V4L Settings
"`Protocol`, `Method`, `Options`, `User`, `Pass`, `Host`, `Port`, `Path`, `SecondPath`, `Width`, `Height`, `Colours`, `Palette`, `Orientation`+0, `Deinterlacing`, "
"`DecoderHWAccelName`, `DecoderHWAccelDevice`, `RTSPDescribe`, "
@ -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;
}
@ -435,7 +435,7 @@ Monitor::Monitor()
/*
std::string load_monitor_sql =
"SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, DecodingEnabled, LinkedMonitors, "
"SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, DecodingEnabled, LinkedMonitors, `EventStartCommand`, `EventEndCommand`, "
"AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS,"
"Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, " // V4L Settings
"Protocol, Method, Options, User, Pass, Host, Port, Path, SecondPath, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, "
@ -489,6 +489,8 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
// See below after save_jpegs for a recalculation of decoding_enabled
ReloadLinkedMonitors(dbrow[col]); col++;
event_start_command = dbrow[col] ? dbrow[col] : ""; col++;
event_end_command = dbrow[col] ? dbrow[col] : ""; col++;
/* "AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS," */
analysis_fps_limit = dbrow[col] ? strtod(dbrow[col], nullptr) : 0.0; col++;
@ -947,7 +949,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 +961,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 +1658,7 @@ void Monitor::CheckAction() {
}
}
void Monitor::UpdateCaptureFPS() {
void Monitor::UpdateFPS() {
if ( fps_report_interval and
(
!(image_count%fps_report_interval)
@ -1675,82 +1677,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 +1864,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;
@ -1922,12 +1875,12 @@ bool Monitor::Analyse() {
if (snap->image) {
// decoder may not have been able to provide an image
if (!ref_image.Buffer()) {
Debug(1, "Assigning instead of Dectecting");
Debug(1, "Assigning instead of Detecting");
ref_image.Assign(*(snap->image));
} 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 +1892,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 +1918,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 +1927,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
@ -2044,6 +1996,12 @@ bool Monitor::Analyse() {
alarm_cause = cause+" Continuous "+alarm_cause;
strncpy(shared_data->alarm_cause, alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1);
SetVideoWriterStartTime(event->StartTime());
if (!event_start_command.empty()) {
if (fork() == 0) {
execlp(event_start_command.c_str(), event_start_command.c_str(), std::to_string(event->Id()).c_str(), nullptr);
Error("Error execing %s", event_start_command.c_str());
}
}
Info("%s: %03d - Opened new event %" PRIu64 ", section start",
name.c_str(), analysis_image_count, event->Id());
@ -2054,26 +2012,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
@ -2133,6 +2092,13 @@ bool Monitor::Analyse() {
delete start_it;
start_it = nullptr;
if (!event_start_command.empty()) {
if (fork() == 0) {
execlp(event_start_command.c_str(), event_start_command.c_str(), std::to_string(event->Id()).c_str(), nullptr);
Error("Error execing %s", event_start_command.c_str());
}
}
Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name.c_str(), analysis_image_count, event->Id());
} else {
shared_data->state = state = ALARM;
@ -2170,8 +2136,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 +2157,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 +2177,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 +2200,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 +2265,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 +2327,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 +2549,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 +2588,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 +2758,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 +2774,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;
}
@ -2838,7 +2801,18 @@ void Monitor::closeEvent() {
Debug(1, "close event thread is not joinable");
}
Debug(1, "Starting thread to close event");
close_event_thread = std::thread([](Event *e){ delete e; }, event);
close_event_thread = std::thread([](Event *e, const std::string &command){
int64_t event_id = e->Id();
delete e;
if (!command.empty()) {
if (fork() == 0) {
execlp(command.c_str(), command.c_str(), std::to_string(event_id).c_str(), nullptr);
Error("Error execing %s", command.c_str());
}
}
}, event, event_end_command);
Debug(1, "Nulling event");
event = nullptr;
if (shared_data) video_store_data->recording = {};

View File

@ -100,7 +100,7 @@ public:
} Deinterlace;
typedef enum {
UNKNOWN=-1,
UNKNOWN,
IDLE,
PREALARM,
ALARM,
@ -404,6 +404,8 @@ protected:
int n_linked_monitors;
MonitorLink **linked_monitors;
std::string event_start_command;
std::string event_end_command;
std::vector<Group *> groups;
@ -546,8 +548,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();

View File

@ -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) {
@ -386,10 +377,10 @@ bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint times
}
bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) {
Image *send_image = prepareImage(image);
if (!config.timestamp_on_capture) {
monitor->TimestampImage(send_image, timestamp);
monitor->TimestampImage(image, timestamp);
}
Image *send_image = prepareImage(image);
fputs("--" BOUNDARY "\r\n", stdout);
if ( type == STREAM_MPEG ) {
@ -863,16 +854,16 @@ void MonitorStream::SingleImage(int scale) {
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
Debug(1, "write index: %d %d", monitor->shared_data->last_write_index, index);
Image *snap_image = monitor->image_buffer[index];
if (!config.timestamp_on_capture) {
monitor->TimestampImage(snap_image,
SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index])));
}
if ( scale != ZM_SCALE_BASE ) {
scaled_image.Assign(*snap_image);
scaled_image.Scale(scale);
snap_image = &scaled_image;
}
if (!config.timestamp_on_capture) {
monitor->TimestampImage(snap_image,
SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index])));
}
snap_image->EncodeJpeg(img_buffer, &img_buffer_size);
fprintf(stdout,

View File

@ -116,14 +116,15 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
, max_video_packet_count);
for (
auto it = ++pktQueue.begin();
it != pktQueue.end() and *it != add_packet;
auto it = ++pktQueue.begin();
it != pktQueue.end() and *it != add_packet;
// iterator is incremented by erase
) {
std::shared_ptr <ZMPacket>zm_packet = *it;
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
if (!lp->trylock()) {
Debug(1, "Found locked packet when trying to free up video packets. Skipping to next one");
Warning("Found locked packet when trying to free up video packets. This basically means that decoding is not keeping up.");
delete lp;
++it;
continue;
@ -209,7 +210,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
@ -312,7 +313,6 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
pktQueue.size());
pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1;
//delete zm_packet;
}
} // end if have at least max_video_packet_count video packets remaining
// We signal on every packet because someday we may analyze sound

View File

@ -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

View File

@ -252,8 +252,15 @@ void HwCapsDetect() {
#elif defined(__arm__)
// ARM processor in 32bit mode
// To see if it supports NEON, we need to get that information from the kernel
#ifdef __linux__
unsigned long auxval = getauxval(AT_HWCAP);
if (auxval & HWCAP_ARM_NEON) {
#elif defined(__FreeBSD__)
unsigned long auxval = 0;
elf_aux_info(AT_HWCAP, &auxval, sizeof(auxval));
if (auxval & HWCAP_NEON) {
#error Unsupported OS.
#endif
Debug(1,"Detected ARM (AArch32) processor with Neon");
neonversion = 1;
} else {

View File

@ -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

View File

@ -878,16 +878,23 @@ std::vector<Zone> Zone::Load(Monitor *monitor) {
continue;
}
if (polygon.Extent().Lo().x_ < 0 || polygon.Extent().Hi().x_ > static_cast<int32>(monitor->Width())
|| polygon.Extent().Lo().y_ < 0 || polygon.Extent().Hi().y_ > static_cast<int32>(monitor->Height())) {
Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), fixing",
if (polygon.Extent().Lo().x_ < 0
||
polygon.Extent().Hi().x_ > static_cast<int32>(monitor->Width())
||
polygon.Extent().Lo().y_ < 0
||
polygon.Extent().Hi().y_ > static_cast<int32>(monitor->Height())) {
Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d) != (%d,%d), fixing",
Id,
Name,
monitor->Name(),
polygon.Extent().Lo().x_,
polygon.Extent().Lo().y_,
polygon.Extent().Hi().x_,
polygon.Extent().Hi().y_);
polygon.Extent().Hi().y_,
monitor->Width(),
monitor->Height());
polygon.Clip(Box(
{0, 0},

View File

@ -220,12 +220,13 @@ int main(int argc, char *argv[]) {
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, SIGHUP);
sigaddset(&block_set, SIGUSR1);
sigaddset(&block_set, SIGUSR2);
struct sigaction sa;
sa.sa_handler = SIG_IGN; //handle signal by ignoring
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGCHLD, &sa, 0) == -1) {
Error("Unable to set SIGCHLD to ignore. There may be zombies.");
}
int result = 0;
int prime_capture_log_count = 0;
@ -268,7 +269,7 @@ int main(int argc, char *argv[]) {
std::this_thread::sleep_for(sleep_time);
}
if (zm_terminate){
if (zm_terminate) {
break;
}
@ -286,7 +287,6 @@ int main(int argc, char *argv[]) {
Microseconds sleep_time = Microseconds(0);
while (!zm_terminate) {
//sigprocmask(SIG_BLOCK, &block_set, 0);
for (size_t i = 0; i < monitors.size(); i++) {
monitors[i]->CheckAction();
@ -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()

View File

@ -116,52 +116,6 @@ else
echo "Defaulting to ZoneMinder upstream git"
GITHUB_FORK="ZoneMinder"
fi;
if [ "$SNAPSHOT" == "stable" ]; then
if [ "$BRANCH" == "" ]; then
#REV=$(git rev-list --tags --max-count=1)
BRANCH=`git describe --tags $(git rev-list --tags --max-count=1)`;
if [ -z "$BRANCH" ]; then
# This should only happen in CI environments where tag info isn't available
BRANCH=`cat version`
echo "Building branch $BRANCH"
fi
if [ "$BRANCH" == "" ]; then
echo "Unable to determine latest stable branch!"
exit 0;
fi
echo "Latest stable branch is $BRANCH";
fi;
else
if [ "$BRANCH" == "" ]; then
echo "Defaulting to master branch";
BRANCH="master";
fi;
if [ "$SNAPSHOT" == "NOW" ]; then
SNAPSHOT=`date +%Y%m%d%H%M%S`;
else
if [ "$SNAPSHOT" == "CURRENT" ]; then
SNAPSHOT="`date +%Y%m%d.`$(git rev-list ${versionhash}..HEAD --count)"
fi;
fi;
fi;
fi
IFS='.' read -r -a VERSION_PARTS <<< "$RELEASE"
if [ "$PPA" == "" ]; then
if [ "$RELEASE" != "" ]; then
# We need to use our official tarball for the original source, so grab it and overwrite our generated one.
if [ "${VERSION_PARTS[0]}.${VERSION_PARTS[1]}" == "1.30" ]; then
PPA="ppa:iconnor/zoneminder-stable"
else
PPA="ppa:iconnor/zoneminder-${VERSION_PARTS[0]}.${VERSION_PARTS[1]}"
fi;
else
if [ "$BRANCH" == "" ]; then
PPA="ppa:iconnor/zoneminder-master";
else
PPA="ppa:iconnor/zoneminder-$BRANCH";
fi;
fi;
fi;
# Instead of cloning from github each time, if we have a fork lying around, update it and pull from there instead.
@ -171,15 +125,8 @@ if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then
cd "${GITHUB_FORK}_ZoneMinder.git"
echo "git fetch..."
git fetch
echo "git checkout $BRANCH"
git checkout $BRANCH
if [ $? -ne 0 ]; then
echo "Failed to switch to branch."
exit 1;
fi;
echo "git pull..."
git pull
cd ../
echo "git clone ${GITHUB_FORK}_ZoneMinder.git ${GITHUB_FORK}_zoneminder_release"
git clone "${GITHUB_FORK}_ZoneMinder.git" "${GITHUB_FORK}_zoneminder_release"
else
@ -192,14 +139,59 @@ else
fi;
cd "${GITHUB_FORK}_zoneminder_release"
git checkout $BRANCH
cd ../
VERSION=`cat ${GITHUB_FORK}_zoneminder_release/version`
if [ "$SNAPSHOT" == "stable" ]; then
if [ "$BRANCH" == "" ]; then
#REV=$(git rev-list --tags --max-count=1)
BRANCH=`git describe --tags $(git rev-list --tags --max-count=1)`;
if [ -z "$BRANCH" ]; then
# This should only happen in CI environments where tag info isn't available
BRANCH=`cat version`
echo "Building branch $BRANCH"
fi
if [ "$BRANCH" == "" ]; then
echo "Unable to determine latest stable branch!"
exit 0;
fi
echo "Latest stable branch is $BRANCH";
fi;
else
if [ "$BRANCH" == "" ]; then
echo "Defaulting to master branch";
BRANCH="master";
fi;
if [ "$SNAPSHOT" == "NOW" ]; then
SNAPSHOT=`date +%Y%m%d%H%M%S`;
else
if [ "$SNAPSHOT" == "CURRENT" ]; then
# git the latest (short) commit hash of the version file
versionhash=$(git log -n1 --pretty=format:%h version)
# Number of commits since the version file was last changed
numcommits=$(git rev-list ${versionhash}..HEAD --count)
SNAPSHOT="`date +%Y%m%d.`$(git rev-list ${versionhash}..HEAD --count)"
fi;
fi;
fi;
echo "git checkout $BRANCH"
git checkout $BRANCH
if [ $? -ne 0 ]; then
echo "Failed to switch to branch."
exit 1;
fi;
echo "git pull..."
git pull
# Grab the ZoneMinder version from the contents of the version file
VERSION=$(cat version)
if [ -z "$VERSION" ]; then
exit 1;
fi;
IFS='.' read -r -a VERSION_PARTS <<< "$VERSION"
cd ../
if [ "$SNAPSHOT" != "stable" ] && [ "$SNAPSHOT" != "" ]; then
VERSION="$VERSION~$SNAPSHOT";
fi;
@ -230,12 +222,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
@ -358,6 +349,22 @@ EOF
fi;
else
SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes";
if [ "$PPA" == "" ]; then
if [ "$RELEASE" != "" ]; then
# We need to use our official tarball for the original source, so grab it and overwrite our generated one.
if [ "${VERSION_PARTS[0]}.${VERSION_PARTS[1]}" == "1.30" ]; then
PPA="ppa:iconnor/zoneminder-stable"
else
PPA="ppa:iconnor/zoneminder-${VERSION_PARTS[0]}.${VERSION_PARTS[1]}"
fi;
else
if [ "$BRANCH" == "" ]; then
PPA="ppa:iconnor/zoneminder-master";
else
PPA="ppa:iconnor/zoneminder-$BRANCH";
fi;
fi;
fi;
dput="Y";
if [ "$INTERACTIVE" != "no" ]; then

View File

@ -1 +1 @@
1.37.1
1.37.5

View File

@ -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 {

View File

@ -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;

View File

@ -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>
';

24
web/ajax/models.php Normal file
View File

@ -0,0 +1,24 @@
<?php
// At the moment this can only return the list of available models given the manufacturer id
$message = '';
//
// INITIALIZE AND CHECK SANITY
//
if (!canView('Monitors')) {
$message = 'Insufficient permissions to view model entries for user '.$user['Username'];
} else if (!isset($_REQUEST['ManufacturerId'])) {
$message = 'This request requires a ManufacturerId to be set';
}
if ($message) {
ajaxError($message);
return;
}
require_once('includes/Model.php');
$models = ZM\Model::find(array('ManufacturerId'=>$_REQUEST['ManufacturerId']), array('order'=>'lower(Name)'));
ajaxResponse(array('models'=>$models));
?>

View File

@ -23,8 +23,6 @@
/**
* Load the API / REST routes
*/
/* Add new API to retrieve camera controls - for PTZ */
/* refer to https://github.com/ZoneMinder/ZoneMinder/issues/799#issuecomment-105233112 */
Router::mapResources('configs');
Router::mapResources('controls');
Router::mapResources('events');
@ -32,7 +30,11 @@
Router::mapResources('groups');
Router::mapResources('host');
Router::mapResources('logs');
Router::mapResources('manufacturers');
Router::mapResources('models');
Router::mapResources('cameramodels');
Router::mapResources('monitors');
Router::mapResources('servers');
Router::mapResources('states');
Router::mapResources('users');
Router::mapResources('zonepresets');

View File

@ -0,0 +1,156 @@
<?php
App::uses('AppController', 'Controller');
/**
* Models Controller
*
* @property Model $Model
* @property PaginatorComponent $Paginator
*/
class CameraModelsController extends AppController {
/**
* Components
*
* @var array
*/
public $components = array('Paginator', 'RequestHandler');
public function beforeFilter() {
parent::beforeFilter();
/*
* A user needs the model data to calculate how to view a monitor, and there really isn't anything sensitive in this data.
* So it has been decided for now to just let everyone read it.
global $user;
$canView = (!$user) || ($user['System'] != 'None');
if ( !$canView ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
*/
}
/**
* index method
*
* @return void
*/
public function index() {
$this->CameraModel->recursive = 0;
$options = '';
$models = $this->CameraModel->find('all', $options);
$this->set(array(
'models' => $models,
'_serialize' => array('models')
));
}
/**
* view method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function view($id = null) {
$this->CameraModel->recursive = 0;
if ( !$this->CameraModel->exists($id) ) {
throw new NotFoundException(__('Invalid model'));
}
$restricted = '';
$options = array('conditions' => array(
array('CameraModel.'.$this->CameraModel->primaryKey => $id),
$restricted
)
);
$model = $this->CameraModel->find('first', $options);
$this->set(array(
'model' => $model,
'_serialize' => array('model')
));
}
/**
* add method
*
* @return void
*/
public function add() {
if ($this->request->is('post')) {
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if (!$canEdit) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->CameraModel->create();
if ($this->CameraModel->save($this->request->data)) {
return $this->flash(__('The model has been saved.'), array('action' => 'index'));
}
}
}
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
$this->CameraModel->id = $id;
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if (!$canEdit) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if (!$this->CameraModel->exists($id)) {
throw new NotFoundException(__('Invalid model'));
}
if ($this->CameraModel->save($this->request->data)) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if (!$canEdit) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->CameraModel->id = $id;
if (!$this->CameraModel->exists()) {
throw new NotFoundException(__('Invalid model'));
}
$this->request->allowMethod('post', 'delete');
if ($this->CameraModel->delete()) {
return $this->flash(__('The model has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The model could not be deleted. Please, try again.'), array('action' => 'index'));
}
}
}

View File

@ -0,0 +1,162 @@
<?php
App::uses('AppController', 'Controller');
/**
* Manufacturers Controller
*
* @property Manufacturer $Manufacturer
* @property PaginatorComponent $Paginator
*/
class ManufacturersController extends AppController {
/**
* Components
*
* @var array
*/
public $components = array('Paginator', 'RequestHandler');
public function beforeFilter() {
parent::beforeFilter();
/*
* A user needs the manufacturer data to calculate how to view a monitor, and there really isn't anything sensitive in this data.
* So it has been decided for now to just let everyone read it.
global $user;
$canView = (!$user) || ($user['System'] != 'None');
if ( !$canView ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
*/
}
/**
* index method
*
* @return void
*/
public function index() {
$this->Manufacturer->recursive = 0;
$options = '';
$manufacturers = $this->Manufacturer->find('all', $options);
$this->set(array(
'manufacturers' => $manufacturers,
'_serialize' => array('manufacturers')
));
}
/**
* view method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function view($id = null) {
$this->Manufacturer->recursive = 0;
if ( !$this->Manufacturer->exists($id) ) {
throw new NotFoundException(__('Invalid manufacturer'));
}
$restricted = '';
$options = array('conditions' => array(
array('Manufacturer.'.$this->Manufacturer->primaryKey => $id),
$restricted
)
);
$manufacturer = $this->Manufacturer->find('first', $options);
$this->set(array(
'manufacturer' => $manufacturer,
'_serialize' => array('manufacturer')
));
}
/**
* add method
*
* @return void
*/
public function add() {
if ( $this->request->is('post') ) {
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Manufacturer->create();
if ( $this->Manufacturer->save($this->request->data) ) {
# Might be nice to send it a start request
#$this->daemonControl($this->Manufacturer->id, 'start', $this->request->data);
return $this->flash(__('The manufacturer has been saved.'), array('action' => 'index'));
}
}
}
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
$this->Manufacturer->id = $id;
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ( !$this->Manufacturer->exists($id) ) {
throw new NotFoundException(__('Invalid manufacturer'));
}
if ( $this->Manufacturer->save($this->request->data) ) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
// - restart this manufacturer after change
#$this->daemonControl($this->Manufacturer->id, 'restart', $this->request->data);
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Manufacturer->id = $id;
if ( !$this->Manufacturer->exists() ) {
throw new NotFoundException(__('Invalid manufacturer'));
}
$this->request->allowMethod('post', 'delete');
#$this->daemonControl($this->Manufacturer->id, 'stop');
if ( $this->Manufacturer->delete() ) {
return $this->flash(__('The manufacturer has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The manufacturer could not be deleted. Please, try again.'), array('action' => 'index'));
}
}
}

View File

@ -89,8 +89,6 @@ class ServersController extends AppController {
$this->Server->create();
if ( $this->Server->save($this->request->data) ) {
# Might be nice to send it a start request
#$this->daemonControl($this->Server->id, 'start', $this->request->data);
return $this->flash(__('The server has been saved.'), array('action' => 'index'));
}
}
@ -126,8 +124,6 @@ class ServersController extends AppController {
'message' => $message,
'_serialize' => array('message')
));
// - restart this server after change
#$this->daemonControl($this->Server->id, 'restart', $this->request->data);
}
/**
@ -151,8 +147,6 @@ class ServersController extends AppController {
}
$this->request->allowMethod('post', 'delete');
#$this->daemonControl($this->Server->id, 'stop');
if ( $this->Server->delete() ) {
return $this->flash(__('The server has been deleted.'), array('action' => 'index'));
} else {

View File

@ -0,0 +1,70 @@
<?php
App::uses('AppModel', 'CameraModel');
/**
* Model CameraModel
*
* @property Name $Name
* @property ManufacturerId $ManufacturerId
*/
class CameraModel extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Models';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'Id';
/**
* Display field
*
* @var string
*/
public $displayField = 'Name';
public $recursive = -1;
/**
* Validation rules
*
* @var array
*/
public $validate = array(
'Name' => array(
'notBlank' => array(
'rule' => array('notBlank'))),
'Id' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* hasMany associations
*
* @var array
*/
public $hasOne = array(
'Manufacturer' => array(
'className' => 'Manufacturer',
'joinTable' => 'Manufacturers',
'foreignKey' => 'Id',
),
);
//var $actsAs = array( 'Containable' );
}

View File

@ -0,0 +1,77 @@
<?php
App::uses('AppModel', 'Model');
/**
* Manufacturer Model
*
* @property Event $Event
* @property Zone $Zone
*/
class Manufacturer extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Manufacturers';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'Id';
/**
* Display field
*
* @var string
*/
public $displayField = 'Name';
public $recursive = -1;
/**
* Validation rules
*
* @var array
*/
public $validate = array(
'Id' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'Name' => array(
'notBlank' => array(
'rule' => array('notBlank'))),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* hasMany associations
*
* @var array
*/
public $hasMany = array(
'Model' => array(
'className' => 'Model',
'foreignKey' => 'ManufacturerId',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}

View File

@ -139,6 +139,16 @@ class Monitor extends AppModel {
'className' => 'Event_Summary',
'foreignKey' => 'MonitorId',
'joinTable' => 'Event_Summaries',
),
'Manufacturer' => array(
'className' => 'Manufacturer',
'foreignKey' => 'Id',
'joinTable' => 'Manufacturers',
),
'CameraModel' => array(
'className' => 'CameraModel',
'foreignKey' => 'Id',
'joinTable' => 'Models',
)
);

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($manufacturer);

View File

@ -0,0 +1 @@
echo json_encode($manufacturers);

View File

@ -0,0 +1 @@
echo json_encode($manufacturer);

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $message));
echo $xml->asXML();

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $servers));
echo $xml->asXML();

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $server));
echo $xml->asXML();

View File

@ -650,6 +650,23 @@ class Event extends ZM_Object {
}
return false;
}
function canEdit($u=null) {
global $user;
if (!$u) $u=$user;
if (!$u) {
# auth turned on and not logged in
return false;
}
if (!empty($u['MonitorIds']) ) {
if (!in_array($this->{'MonitorId'}, explode(',', $u['MonitorIds']))) {
return false;
}
}
if ($u['Events'] != 'Edit') {
return false;
}
return true;
}
} # end class
?>

View File

@ -0,0 +1,23 @@
<?php
namespace ZM;
require_once('database.php');
require_once('Object.php');
class Manufacturer extends ZM_Object {
protected static $table = 'Manufacturers';
protected $defaults = array(
'Id' => null,
'Name' => '',
);
public static function find( $parameters = array(), $options = array() ) {
return ZM_Object::_find(get_class(), $parameters, $options);
}
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(get_class(), $parameters, $options);
}
} # end class Manufacturer
?>

23
web/includes/Model.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace ZM;
require_once('database.php');
require_once('Object.php');
class Model extends ZM_Object {
protected static $table = 'Models';
protected $defaults = array(
'Id' => null,
'Name' => '',
'ManufacturerId' => null,
);
public static function find( $parameters = array(), $options = array() ) {
return ZM_Object::_find(get_class(), $parameters, $options);
}
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(get_class(), $parameters, $options);
}
} # end class Model
?>

View File

@ -1,11 +1,13 @@
<?php
namespace ZM;
require_once('database.php');
require_once('Server.php');
require_once('Object.php');
require_once('Control.php');
require_once('Storage.php');
require_once('Group.php');
require_once('Manufacturer.php');
require_once('Model.php');
require_once('Server.php');
require_once('Storage.php');
$FunctionTypes = null;
@ -47,12 +49,16 @@ class Monitor extends ZM_Object {
'Notes' => '',
'ServerId' => 0,
'StorageId' => 0,
'ManufacturerId' => null,
'ModelId' => null,
'Type' => 'Ffmpeg',
'Function' => 'Mocord',
'Enabled' => array('type'=>'boolean','default'=>1),
'DecodingEnabled' => array('type'=>'boolean','default'=>1),
'LinkedMonitors' => array('type'=>'set', 'default'=>null),
'Triggers' => array('type'=>'set','default'=>''),
'EventStartCommand' => '',
'EventEndCommand' => '',
'ONVIF_URL' => '',
'ONVIF_Username' => '',
'ONVIF_Password' => '',
@ -495,6 +501,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
@ -682,5 +692,29 @@ class Monitor extends ZM_Object {
function DisableAlarms() {
$output = $this->AlarmCommand('disable');
}
function Model() {
if (!property_exists($this, 'Model')) {
if ($this->{'ModelId'}) {
$this->{'Model'} = Model::find_one(array('Id'=>$this->ModelId()));
if (!$this->{'Model'})
$this->{'Model'} = new Model();
} else {
$this->{'Model'} = new Model();
}
}
return $this->{'Model'};
}
function Manufacturer() {
if (!property_exists($this, 'Manufacturer')) {
if ($this->{'ManufacturerId'}) {
$this->{'Manufacturer'} = Manufacturer::find_one(array('Id'=>$this->ManufacturerId()));
if (!$this->{'Manufacturer'})
$this->{'Manufacturer'} = new Manufacturer();
} else {
$this->{'Manufacturer'} = new Manufacturer();
}
}
return $this->{'Manufacturer'};
}
} // end class Monitor
?>

View File

@ -28,7 +28,7 @@ class ZM_Object {
$this->{$k} = $v;
}
global $object_cache;
if ( ! isset($object_cache[$class]) ) {
if (!isset($object_cache[$class])) {
$object_cache[$class] = array();
}
$cache = &$object_cache[$class];
@ -103,13 +103,13 @@ class ZM_Object {
}
$sql .= implode(' AND ', $fields );
}
if ( $options ) {
if ( isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
if ($options) {
if (isset($options['order'])) {
$sql .= ' ORDER BY '.$options['order'];
}
if ( isset($options['limit']) ) {
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
$sql .= ' LIMIT ' . $options['limit'];
if (isset($options['limit'])) {
if (is_integer($options['limit']) or ctype_digit($options['limit'])) {
$sql .= ' LIMIT '.$options['limit'];
} else {
$backTrace = debug_backtrace();
Error('Invalid value for limit('.$options['limit'].') passed to '.get_class()."::find from ".print_r($backTrace,true));
@ -119,8 +119,8 @@ class ZM_Object {
}
$rows = dbFetchAll($sql, NULL, $values);
$results = array();
if ( $rows ) {
foreach ( $rows as $row ) {
if ($rows) {
foreach ($rows as $row) {
array_push($results , new $class($row));
}
}
@ -129,7 +129,7 @@ class ZM_Object {
public static function _find_one($class, $parameters = array(), $options = array() ) {
global $object_cache;
if ( ! isset($object_cache[$class]) ) {
if (!isset($object_cache[$class])) {
$object_cache[$class] = array();
}
$cache = &$object_cache[$class];
@ -179,11 +179,11 @@ class ZM_Object {
}
public function set($data) {
foreach ( $data as $field => $value ) {
if ( method_exists($this, $field) and is_callable(array($this, $field), false) ) {
foreach ($data as $field => $value) {
if (method_exists($this, $field) and is_callable(array($this, $field), false)) {
$this->$field($value);
} else {
if ( is_array($value) ) {
if (is_array($value)) {
# perhaps should turn into a comma-separated string
$this->{$field} = implode(',', $value);
} else if (is_string($value)) {
@ -212,11 +212,11 @@ class ZM_Object {
} else {
$this->{$field} = $value;
}
} else if ( is_integer($value) ) {
} else if (is_integer($value)) {
$this->{$field} = $value;
} else if ( is_bool($value) ) {
} else if (is_bool($value)) {
$this->{$field} = $value;
} else if ( is_null($value) ) {
} else if (is_null($value)) {
$this->{$field} = $value;
} else {
Error("Unknown type $field => $value of var " . gettype($value));
@ -307,7 +307,7 @@ class ZM_Object {
$class = get_class($this);
$table = $class::$table;
if ( $new_values ) {
if ($new_values) {
$this->set($new_values);
}

View File

@ -19,33 +19,66 @@
//
// Monitor edit actions, monitor id derived, require edit permissions for that monitor
if ( !canEdit('Monitors') ) {
if (!canEdit('Monitors')) {
ZM\Warning('Monitor actions require Monitors Permissions');
return;
}
if ( $action == 'save' ) {
global $error_message;
if ($action == 'save') {
$mid = 0;
if ( !empty($_REQUEST['mid']) ) {
if (!empty($_REQUEST['mid'])) {
$mid = validInt($_REQUEST['mid']);
if ( !canEdit('Monitors', $mid) ) {
if (!canEdit('Monitors', $mid)) {
ZM\Warning('You do not have permission to edit this monitor');
return;
}
if ( ZM_OPT_X10 ) {
if (ZM_OPT_X10) {
$x10Monitor = dbFetchOne('SELECT * FROM TriggersX10 WHERE MonitorId=?', NULL, array($mid));
if ( !$x10Monitor ) $x10Monitor = array();
if (!$x10Monitor) $x10Monitor = array();
}
} else {
if ( $user['MonitorIds'] ) {
if ($user['MonitorIds']) {
ZM\Warning('You are restricted to certain monitors so cannot add a new one.');
return;
}
if ( ZM_OPT_X10 ) {
if (ZM_OPT_X10) {
$x10Monitor = array();
}
}
# For convenience
$newMonitor = $_REQUEST['newMonitor'];
ZM\Debug("newMonitor: ". print_r($newMonitor, true));
if (!$newMonitor['ManufacturerId'] and ($newMonitor['Manufacturer'] != '')) {
# Need to add a new Manufacturer entry
$newManufacturer = ZM\Manufacturer::find_one(array('Name'=>$newMonitor['Manufacturer']));
if (!$newManufacturer) {
$newManufacturer = new ZM\Manufacturer();
if (!$newManufacturer->save(array('Name'=>$newMonitor['Manufacturer']))) {
$error_message .= "Error saving new Manufacturer: " . $newManufacturer->get_last_error().'</br>';
}
}
$newMonitor['ManufacturerId'] = $newManufacturer->Id();
}
if (!$newMonitor['ModelId'] and ($newMonitor['Model'] != '')) {
# Need to add a new Model entry
$newModel = ZM\Model::find_one(array('Name'=>$newMonitor['Model']));
if (!$newModel) {
$newModel = new ZM\Model();
if (!$newModel->save(array(
'Name'=>$newMonitor['Model'],
'ManufacturerId'=>$newMonitor['ManufacturerId']
))) {
$error_message .= "Error saving new Model: " . $newModel->get_last_error().'</br>';
}
}
$newMonitor['ModelId'] = $newModel->Id();
}
$monitor = new ZM\Monitor($mid);
// Define a field type for anything that's not simple text equivalent
@ -68,33 +101,35 @@ if ( $action == 'save' ) {
# Checkboxes don't return an element in the POST data, so won't be present in newMonitor.
# So force a value for these fields
foreach ( $types as $field => $value ) {
if ( ! isset($_REQUEST['newMonitor'][$field] ) ) {
$_REQUEST['newMonitor'][$field] = $value;
foreach ($types as $field => $value) {
if (!isset($newMonitor[$field])) {
$newMonitor[$field] = $value;
}
} # end foreach type
if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) {
$_REQUEST['newMonitor']['ServerId'] = dbFetchOne(
if ($newMonitor['ServerId'] == 'auto') {
$newMonitor['ServerId'] = dbFetchOne(
'SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id');
ZM\Debug('Auto selecting server: Got ' . $_REQUEST['newMonitor']['ServerId']);
if ( ( !$_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) {
$_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID;
ZM\Debug('Auto selecting server: Got ' . $newMonitor['ServerId']);
if ((!$newMonitor['ServerId']) and defined('ZM_SERVER_ID')) {
$newMonitor['ServerId'] = ZM_SERVER_ID;
ZM\Debug('Auto selecting server to ' . ZM_SERVER_ID);
}
}
$changes = $monitor->changes($_REQUEST['newMonitor']);
ZM\Debug("newMonitor: ". print_r($newMonitor, true));
$changes = $monitor->changes($newMonitor);
ZM\Debug("Changes: ". print_r($changes, true));
$restart = false;
if ( count($changes) ) {
if (count($changes)) {
// monitor->Id() has a value when the db record exists
if ( $monitor->Id() ) {
if ($monitor->Id()) {
# If we change anything that changes the shared mem size, zma can complain. So let's stop first.
if ( $monitor->Type() != 'WebSite' ) {
if ($monitor->Type() != 'WebSite') {
$monitor->zmcControl('stop');
if ( $monitor->Controllable() ) {
if ($monitor->Controllable()) {
$monitor->sendControlCommand('stop');
}
}
@ -103,8 +138,7 @@ if ( $action == 'save' ) {
$oldW = $monitor->Width();
$oldH = $monitor->Height();
if ( $monitor->save($changes) ) {
if ($monitor->save($changes)) {
// Groups will be added below
if ( isset($changes['Name']) or isset($changes['StorageId']) ) {
// creating symlinks when symlink already exists reports errors, but is perfectly ok
@ -112,28 +146,28 @@ if ( $action == 'save' ) {
$OldStorage = $monitor->Storage();
$saferOldName = basename($monitor->Name());
if ( file_exists($OldStorage->Path().'/'.$saferOldName) )
if (file_exists($OldStorage->Path().'/'.$saferOldName))
unlink($OldStorage->Path().'/'.$saferOldName);
$NewStorage = new ZM\Storage($_REQUEST['newMonitor']['StorageId']);
if ( !file_exists($NewStorage->Path().'/'.$mid) ) {
if ( !mkdir($NewStorage->Path().'/'.$mid, 0755) ) {
ZM\Error('Unable to mkdir ' . $NewStorage->Path().'/'.$mid);
$NewStorage = new ZM\Storage($newMonitor['StorageId']);
if (!file_exists($NewStorage->Path().'/'.$mid)) {
if (!mkdir($NewStorage->Path().'/'.$mid, 0755)) {
ZM\Error('Unable to mkdir '.$NewStorage->Path().'/'.$mid);
}
}
$saferNewName = basename($_REQUEST['newMonitor']['Name']);
$saferNewName = basename($newMonitor['Name']);
$link_path = $NewStorage->Path().'/'.$saferNewName;
// Use a relative path for the target so the link continues to work from backups or directory changes.
if ( !symlink($mid, $link_path) ) {
if ( ! ( file_exists($link_path) and is_link($link_path) ) ) {
if (!symlink($mid, $link_path)) {
if (!(file_exists($link_path) and is_link($link_path))) {
ZM\Warning('Unable to symlink ' . $NewStorage->Path().'/'.$mid . ' to ' . $NewStorage->Path().'/'.$saferNewName);
}
}
} // end if Name or Storage Area Change
if ( isset($changes['Width']) || isset($changes['Height']) ) {
$newW = $_REQUEST['newMonitor']['Width'];
$newH = $_REQUEST['newMonitor']['Height'];
if (isset($changes['Width']) || isset($changes['Height'])) {
$newW = $newMonitor['Width'];
$newH = $newMonitor['Height'];
$zones = dbFetchAll('SELECT * FROM Zones WHERE MonitorId=?', NULL, array($mid));
@ -204,8 +238,7 @@ if ( $action == 'save' ) {
} // end if rotation or just size change
} // end if changes in width or height
} else {
global $error_message;
$error_message = dbError('unknown');
$error_message .= $monitor->get_last_error();
} // end if successful save
$restart = true;
} else { // new monitor
@ -217,14 +250,27 @@ if ( $action == 'save' ) {
if ( $monitor->insert($changes) ) {
$mid = $monitor->Id();
$zoneArea = $_REQUEST['newMonitor']['Width'] * $_REQUEST['newMonitor']['Height'];
dbQuery("INSERT INTO Zones SET MonitorId = ?, Name = 'All', Type = 'Active', Units = 'Percent', NumCoords = 4, Coords = ?, Area=?, AlarmRGB = 0xff0000, CheckMethod = 'Blobs', MinPixelThreshold = 25, MinAlarmPixels=?, MaxAlarmPixels=?, FilterX = 3, FilterY = 3, MinFilterPixels=?, MaxFilterPixels=?, MinBlobPixels=?, MinBlobs = 1", array( $mid, sprintf( "%d,%d %d,%d %d,%d %d,%d", 0, 0, $_REQUEST['newMonitor']['Width']-1, 0, $_REQUEST['newMonitor']['Width']-1, $_REQUEST['newMonitor']['Height']-1, 0, $_REQUEST['newMonitor']['Height']-1 ), $zoneArea, intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*2)/100) ) );
//$view = 'none';
$zoneArea = $newMonitor['Width'] * $newMonitor['Height'];
dbQuery("INSERT INTO Zones SET MonitorId = ?, Name = 'All', Type = 'Active', Units = 'Percent', NumCoords = 4, Coords = ?, Area=?, AlarmRGB = 0xff0000, CheckMethod = 'Blobs', MinPixelThreshold = 25, MinAlarmPixels=?, MaxAlarmPixels=?, FilterX = 3, FilterY = 3, MinFilterPixels=?, MaxFilterPixels=?, MinBlobPixels=?, MinBlobs = 1", array( $mid,
sprintf( '%d,%d %d,%d %d,%d %d,%d', 0, 0,
$newMonitor['Width']-1,
0,
$newMonitor['Width']-1,
$newMonitor['Height']-1,
0,
$newMonitor['Height']-1),
$zoneArea,
intval(($zoneArea*3)/100),
intval(($zoneArea*75)/100),
intval(($zoneArea*3)/100),
intval(($zoneArea*75)/100),
intval(($zoneArea*2)/100)
));
$Storage = $monitor->Storage();
error_reporting(0);
mkdir($Storage->Path().'/'.$mid, 0755);
$saferName = basename($_REQUEST['newMonitor']['Name']);
$saferName = basename($newMonitor['Name']);
symlink($mid, $Storage->Path().'/'.$saferName);
} else {

View File

@ -19,24 +19,27 @@
//
// Monitor edit actions, monitor id derived, require edit permissions for that monitor
if ( ! canEdit('Monitors') ) {
if (!canEdit('Monitors')) {
ZM\Warning("Monitor actions require Monitors Permissions");
return;
}
if ( $action == 'save' ) {
foreach ( $_REQUEST['mids'] as $mid ) {
if ($action == 'save') {
foreach ($_REQUEST['mids'] as $mid) {
$mid = ValidInt($mid);
if ( ! canEdit('Monitors', $mid) ) {
ZM\Warning("Cannot edit monitor $mid");
if (!canEdit('Monitors', $mid)) {
ZM\Warning('Cannot edit monitor '.$mid);
continue;
}
$Monitor = new ZM\Monitor($mid);
if ( $Monitor->Type() != 'WebSite' ) {
if ($Monitor->Type() != 'WebSite') {
$Monitor->zmcControl('stop');
}
$Monitor->save($_REQUEST['newMonitor']);
if ( $Monitor->Function() != 'None' && $Monitor->Type() != 'WebSite' ) {
if (!$Monitor->save($_REQUEST['newMonitor'])) {
global $error_message;
$error_message .= 'Error saving monitor: ' . $Monitor->get_last_error().'<br/>';
}
if ($Monitor->Function() != 'None' && $Monitor->Type() != 'WebSite') {
$Monitor->zmcControl('start');
}
} // end foreach mid

View File

@ -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;
}

View File

@ -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;
}

View File

@ -663,8 +663,33 @@ $SLANG = array(
'PrivacyCookiesText' => 'Whether you use a web browser or a mobile app to communicate with the ZoneMinder server, a ZMSESSID cookie is created on the client to uniquely identify a session with the ZoneMinder server. ZmCSS and zmSkin cookies are created to remember your style and skin choices.',
'PrivacyTelemetry' => 'Telemetry',
'PrivacyTelemetryText' => 'Because ZoneMinder is open-source, anyone can install it without registering. This makes it difficult to answer questions such as: how many systems are out there, what is the largest system out there, what kind of systems are out there, or where are these systems located? Knowing the answers to these questions, helps users who ask us these questions, and it helps us set priorities based on the majority user base.',
'PrivacyTelemetryList' => 'The ZoneMinder Telemetry daemon collects the following data about your system:<ul><li>A unique identifier (UUID) <li>City based location is gathered by querying <a href="https://ipinfo.io/geo">ipinfo.io</a>. City, region, country, latitude, and longitude parameters are saved. The latitude and longitude coordinates are accurate down to the city or town level only!<li>Current time<li>Total number of monitors<li>Total number of events<li>System architecture<li>Operating system kernel, distro, and distro version<li>Version of ZoneMinder<li>Total amount of memory<li>Number of cpu cores</ul>',
'PrivacyMonitorList' => 'The following configuration parameters from each monitor are collected:<ul><li>Id<li>Name<li>Type<li>Function<li>Width<li>Height<li>Colours<li>MaxFPS<li>AlarmMaxFPS</ul>',
'PrivacyTelemetryList' => 'The ZoneMinder Telemetry daemon collects the following data about your system:
<ul>
<li>A unique identifier (UUID)</li>
<li>City based location is gathered by querying <a href="https://ipinfo.io/geo">ipinfo.io</a>. City, region, country, latitude, and longitude parameters are saved. The latitude and longitude coordinates are accurate down to the city or town level only!</li>
<li>Current time</li>
<li>Total number of monitors</li>
<li>Total number of events</li>
<li>System architecture</li>
<li>Operating system kernel, distro, and distro version</li>
<li>Version of ZoneMinder</li>
<li>Total amount of memory</li>
<li>Number of cpu cores</li>
</ul>',
'PrivacyMonitorList' => 'The following configuration parameters from each monitor are collected:
<ul>
<li>Id</li>
<li>Name</li>
<li>Manufacturer</li>
<li>Model</li>
<li>Type</li>
<li>Function</li>
<li>Width</li>
<li>Height</li>
<li>Colours</li>
<li>MaxFPS</li>
<li>AlarmMaxFPS</li>
</ul>',
'PrivacyConclusionText' => 'We are <u>NOT</u> collecting any image specific data from your cameras. We dont know what your cameras are watching. This data will not be sold or used for any purpose not stated herein. By clicking accept, you agree to send us this data to help make ZoneMinder a better product. By clicking decline, you can still freely use ZoneMinder and all its features.',
'Probe' => 'Probe',
'ProfileProbe' => 'Stream Probe',

View File

@ -786,7 +786,7 @@ function exportFileList(
}
closedir($dir);
}
ZM\Debug(print_r($files, true));
ZM\Debug('All available files: '.print_r($files, true));
$exportFileList = array();
@ -843,6 +843,18 @@ function exportFileList(
ZM\Debug('Not including frame images');
} # end if exportImages
if ($exportVideo) {
$filesLeft = array();
foreach ($files as $file) {
if (preg_match('/\.(?:mpg|mpeg|mov|swf|mp4|mkv|avi|asf|3gp)$/', $file)) {
$exportFileList[$file] = $file;
} else {
$filesLeft[$file] = $file;
}
}
$files = $filesLeft;
}
if ($exportMisc) {
foreach ($files as $file) {
$exportFileList[$file] = $file;

View File

@ -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();
}
}

View File

@ -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) ) {

View File

@ -178,7 +178,6 @@ $html .= '</span>
' .
( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : '' ).' ORDER BY Sequence ASC';
$monitors = dbFetchAll($sql, null, $values);
ZM\Debug(print_r($monitors, true));
$displayMonitors = array();
$monitors_dropdown = array();

View File

@ -150,6 +150,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
<button id="editBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Edit') ?>" disabled><i class="fa fa-pencil"></i></button>
<button id="exportBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Export') ?>"><i class="fa fa-external-link"></i></button>
<a id="downloadBtn" class="btn btn-normal" href="<?php echo $Event->getStreamSrc(array('mode'=>'mp4'),'&amp;')?>"
title="<?php echo translate('Download'). ' ' . $Event->DefaultVideo() ?>"
download
<?php echo $Event->DefaultVideo() ? '' : 'style="display:none;"' ?>
><i class="fa fa-download"></i></a>

View File

@ -152,7 +152,7 @@ $booleanValues = array(
$focusWindow = true;
$storageareas = array('' => 'All') + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage');
$storageareas = array('' => array('Name'=>'NULL Unspecified'), '0' => array('Name'=>'Zero')) + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage');
$weekdays = array();
for ( $i = 0; $i < 7; $i++ ) {

View File

@ -657,6 +657,7 @@ function getFrameResponse(respObj, respText) {
function frameQuery(eventId, frameId, loadImage) {
var data = {};
if (auth_hash) data.auth = auth_hash;
data.loopback = loadImage;
data.id = {eventId, frameId};
@ -772,8 +773,9 @@ function manageDelConfirmModalBtns() {
return;
}
pauseClicked();
evt.preventDefault();
$j.getJSON(thisUrl + '?request=event&task=delete&id='+eventData.Id)
$j.getJSON(thisUrl + '?request=event&action=delete&id='+eventData.Id)
.done(function(data) {
$j('#deleteConfirm').modal('hide');
streamNext(true);

View File

@ -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});
@ -59,13 +63,13 @@ function processRows(rows) {
row.Id = '<a href="?view=event&amp;eid=' + eid + filterQuery + sortQuery + '&amp;page=1">' + eid + '</a>';
row.Name = '<a href="?view=event&amp;eid=' + eid + filterQuery + sortQuery + '&amp;page=1">' + row.Name + '</a>' +
'<br/><div class="small text-nowrap text-muted">' + archived + emailed + '</div>';
'<br/><div class="small text-muted">' + archived + emailed + '</div>';
if ( canEdit.Monitors ) row.Monitor = '<a href="?view=event&amp;eid=' + eid + '">' + row.Monitor + '</a>';
if ( canEdit.Events ) row.Cause = '<a href="#" title="' + row.Notes + '" class="eDetailLink" data-eid="' + eid + '">' + row.Cause + '</a>';
if ( row.Notes.indexOf('detected:') >= 0 ) {
row.Cause = row.Cause + '<a href="#" class="objDetectLink" data-eid=' +eid+ '><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></div></a>';
row.Cause = row.Cause + '<a href="#" class="objDetectLink" data-eid=' +eid+ '><div class="small text-muted"><u>' + row.Notes + '</u></div></div></a>';
} else if ( row.Notes != 'Forced Web: ' ) {
row.Cause = row.Cause + '<br/><div class="small text-nowrap text-muted">' + row.Notes + '</div>';
row.Cause = row.Cause + '<br/><div class="small text-muted">' + row.Notes + '</div>';
}
row.Frames = '<a href="?view=frames&amp;eid=' + eid + '">' + row.Frames + '</a>';
row.AlarmFrames = '<a href="?view=frames&amp;eid=' + eid + '">' + row.AlarmFrames + '</a>';

View File

@ -324,7 +324,6 @@ function update_estimated_ram_use() {
var max_buffer_count = parseInt(document.querySelectorAll('input[name="newMonitor[MaxImageBufferCount]"]')[0].value);
if (max_buffer_count) {
var max_buffer_size = (min_buffer_count + max_buffer_count) * width * height * colours;
console.log(max_buffer_size);
document.getElementById('estimated_ram_use').innerHTML += ' Max: ' + human_filesize(max_buffer_size);
} else {
document.getElementById('estimated_ram_use').innerHTML += ' Max: Unlimited';
@ -346,4 +345,85 @@ function getLocation() {
}
}
function populate_models(ManufacturerId) {
const dropdown = $j('[name="newMonitor[ModelId]"]');
if (!dropdown.length) {
console.log("No element found for ModelId");
return;
}
dropdown.empty();
dropdown.append('<option value="" selected="true">Unknown</option>');
dropdown.prop('selectedIndex', 0);
if (ManufacturerId) {
// Populate dropdown with list of provinces
$j.getJSON(thisUrl+'?request=models&ManufacturerId='+ManufacturerId, function(data) {
if (data.result == 'Ok') {
$j.each(data.models, function(key, entry) {
dropdown.append($j('<option></option>').attr('value', entry.Id).text(entry.Name));
});
dropdown.chosen("destroy");
dropdown.chosen();
} else {
alert(data.result);
}
});
}
dropdown.chosen("destroy");
dropdown.chosen();
}
function ManufacturerId_onchange(ManufacturerId_select) {
if (ManufacturerId_select.value) {
ManufacturerId_select.form.elements['newMonitor[Manufacturer]'].style['display'] = 'none';
populate_models(ManufacturerId_select.value);
} else {
ManufacturerId_select.form.elements['newMonitor[Manufacturer]'].style['display'] = 'inline';
// Set models dropdown to Unknown, text area visible
const ModelId_dropdown = $j('[name="newMonitor[ModelId]"]');
ModelId_dropdown.empty();
ModelId_dropdown.append('<option selected="true">Unknown</option>');
ModelId_dropdown.prop('selectedIndex', 0);
$j('[name="newMonitor[Model]"]').show();
}
}
function select_by_value_case_insensitive(dropdown, value) {
const test_value = value.toLowerCase();
for (i=1; i < dropdown.options.length; i++) {
if (dropdown.options[i].text.toLowerCase() == test_value) {
dropdown.selectedIndex = i;
dropdown.options[i].selected = true;
$j(dropdown).chosen("destroy").chosen();
return;
}
}
if (dropdown.selectedIndex != 0) {
dropdown.selectedIndex = 0;
$j(dropdown).chosen("destroy").chosen();
}
}
function Manufacturer_onchange(input) {
if (!input.value) {
return;
}
ManufacturerId_select = input.form.elements['newMonitor[ManufacturerId]'];
select_by_value_case_insensitive(ManufacturerId_select, input.value);
populate_models(ManufacturerId_select.value);
}
function ModelId_onchange(ModelId_select) {
if (parseInt(ModelId_select.value)) {
$j('[name="newMonitor[Model]"]').hide();
} else {
$j('[name="newMonitor[Model]"]').show();
}
}
function Model_onchange(input) {
select_by_value_case_insensitive(input.form.elements['newMonitor[ModelId]'], input.value);
}
window.addEventListener('DOMContentLoaded', initPage);

View File

@ -317,5 +317,10 @@ function initPage() {
}
selectLayout('#zmMontageLayout');
}
function watchFullscreen() {
const content = document.getElementById('content');
openFullscreen(content);
}
// Kick everything off
$j(document).ready(initPage);

View File

@ -57,7 +57,7 @@ function getFrame(monId, time, last_Frame) {
var events_for_monitor = events_by_monitor_id[monId];
if ( !events_for_monitor ) {
console.log("No events for monitor " + monId);
//console.log("No events for monitor " + monId);
return;
}
@ -648,8 +648,11 @@ function setSpeed(speed_index) {
}
function setLive(value) {
// When we submit the context etc goes away but we may still be trying to update
// So kill the timer.
clearInterval(timerObj);
liveMode = value;
var form = $j('#montagereview_form')[0];
var form = document.getElementById('montagereview_form');
form.elements['live'].value = value;
form.submit();
return false;
@ -985,6 +988,19 @@ function initPage() {
});
});
if ( !liveMode ) {
canvas = document.getElementById('timeline');
canvas.addEventListener('mousemove', mmove, false);
canvas.addEventListener('touchmove', tmove, false);
canvas.addEventListener('mousedown', mdown, false);
canvas.addEventListener('mouseup', mup, false);
canvas.addEventListener('mouseout', mout, false);
ctx = canvas.getContext('2d');
drawGraph();
}
for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) {
var monId = monitorPtr[i];
if ( !monId ) continue;
@ -1006,18 +1022,6 @@ function initPage() {
}
} // end foreach monitor
if ( !liveMode ) {
canvas = document.getElementById('timeline');
canvas.addEventListener('mousemove', mmove, false);
canvas.addEventListener('touchmove', tmove, false);
canvas.addEventListener('mousedown', mdown, false);
canvas.addEventListener('mouseup', mup, false);
canvas.addEventListener('mouseout', mout, false);
ctx = canvas.getContext('2d');
drawGraph();
}
setSpeed(speedIndex);
//setFit(fitMode); // will redraw
//setLive(liveMode); // will redraw

View File

@ -239,6 +239,6 @@ echo "];\n";
var cWidth; // save canvas width
var cHeight; // save canvas height
var canvas; // global canvas definition so we don't have to keep looking it up
var ctx;
var ctx = null;
var underSlider; // use this to hold what is hidden by the slider
var underSliderX; // Where the above was taken from (left side, Y is zero)

View File

@ -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)

View File

@ -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);

View File

@ -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') ?>",
};

View File

@ -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);
}

View File

@ -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() ?>'
};

View File

@ -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);

View File

@ -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') ?>";

View File

@ -453,7 +453,7 @@ foreach ( $tabs as $name=>$value ) {
switch ( $name ) {
case 'general' :
{
if (!$monitor->Id()) {
if (!$monitor->Id() and count($monitors)) {
$monitor_ids = array();
foreach ($monitors as $m) { $monitor_ids[] = $m['Id']; }
$available_monitor_ids = array_diff(range(min($monitor_ids),max($monitor_ids)), $monitor_ids);
@ -461,13 +461,16 @@ 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
} # end if ! $monitor->Id()
} # end if ! $monitor->Id() and count($monitors)
?>
<tr class="Name">
<td class="text-right pr-3"><?php echo translate('Name') ?></td>
@ -477,6 +480,44 @@ switch ( $name ) {
<td class="text-right pr-3"><?php echo translate('Notes') ?></td>
<td><textarea name="newMonitor[Notes]" rows="4"><?php echo validHtmlStr($monitor->Notes()) ?></textarea></td>
</tr>
<tr class="Manufacturer">
<td class="text-right pr-3"><?php echo translate('Manufacturer') ?></td>
<td>
<?php
require_once('includes/Manufacturer.php');
$manufacturers = array(''=>translate('Unknown'));
foreach ( ZM\Manufacturer::find( null, array('order'=>'lower(Name)')) as $Manufacturer ) {
$manufacturers[$Manufacturer->Id()] = $Manufacturer->Name();
}
echo htmlSelect('newMonitor[ManufacturerId]', $manufacturers, $monitor->ManufacturerId(),
array('class'=>'chosen','data-on-change-this'=>'ManufacturerId_onchange'));
?>
<input type="text" name="newMonitor[Manufacturer]"
placeholder="enter new manufacturer name"
value="<?php echo $monitor->Manufacturer()->Name() ?>"<?php echo $monitor->ManufacturerId() ? ' style="display:none"' : '' ?>
data-on-input-this="Manufacturer_onchange"
/>
</td>
</tr>
<tr class="Model">
<td class="text-right pr-3"><?php echo translate('Model') ?></td>
<td>
<?php
require_once('includes/Model.php');
$models = array(''=>translate('Unknown'));
foreach ( ZM\Model::find(array('ManufacturerId'=>$monitor->ManufacturerId()), array('order'=>'lower(Name)')) as $Model ) {
$models[$Model->Id()] = $Model->Name();
}
echo htmlSelect('newMonitor[ModelId]', $models, $monitor->ModelId(),
array('class'=>'chosen', 'data-on-change-this'=>'ModelId_onchange'));
?>
<input type="text" name="newMonitor[Model]"
placeholder="enter new model name"
value="<?php echo $monitor->Model()->Name() ?>"<?php echo $monitor->ModelId() ? ' style="display:none"':'' ?>
data-on-input-this="Model_onchange"
/>
</td>
</tr>
<tr>
<td class="text-right pr-3"><?php echo translate('Server') ?></td><td>
<?php
@ -634,6 +675,14 @@ switch ( $name ) {
}
?>
</td></tr>
<tr>
<td class="text-right pr-3"><?php echo translate('Event Start Command') ?></td>
<td><input type="text" name="newMonitor[EventStartCommand]" value="<?php echo validHtmlStr($monitor->EventStartCommand()) ?>" /></td>
</tr>
<tr>
<td class="text-right pr-3"><?php echo translate('Event End Command') ?></td>
<td><input type="text" name="newMonitor[EventEndCommand]" value="<?php echo validHtmlStr($monitor->EventEndCommand()) ?>" /></td>
</tr>
<?php
}
break;

View File

@ -206,6 +206,9 @@ if ( canView('System') ) {
&nbsp;<?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>

View File

@ -44,8 +44,9 @@ $tabs['medband'] = translate('MediumBW');
$tabs['lowband'] = translate('LowBW');
$tabs['users'] = translate('Users');
$tabs['control'] = translate('Control');
$tabs['privacy'] = translate('Privacy');
if ( isset($_REQUEST['tab']) )
if (isset($_REQUEST['tab']))
$tab = validHtmlStr($_REQUEST['tab']);
else
$tab = 'system';
@ -53,7 +54,6 @@ else
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Options'));
?>
<body>
<?php echo getNavBarHTML(); ?>
@ -62,7 +62,7 @@ xhtmlHeaders(__FILE__, translate('Options'));
<nav id="sidebar">
<ul class="nav nav-pills flex-column h-100">
<?php
foreach ( $tabs as $name=>$value ) {
foreach ($tabs as $name=>$value) {
?>
<li class="nav-item form-control-sm my-1"><a class="nav-link<?php echo $tab == $name ? ' active' : '' ?>" href="?view=<?php echo $view ?>&amp;tab=<?php echo $name ?>"><?php echo $value ?></a></li>
<?php
@ -194,6 +194,14 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as
}
// Have to do this
header('Location: '.$redirect);
} else if ($tab == 'privacy') {
if (canView('System')) {
$redirect = '?view=privacy';
} else {
$redirect = '?view=error';
}
// Have to do this
header('Location: '.$redirect);
} else if ( $tab == 'servers' ) {
?>
<form name="serversForm" method="post" action="?">

View File

@ -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
?>

View File

@ -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&amp;mid=<?php echo $mid ?>&amp;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') ?>:&nbsp;<span id="stateValue<?php echo $monitor->Id() ?>"></span>&nbsp;-&nbsp;<span id="fpsValue<?php echo $monitor->Id() ?>"></span>&nbsp;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'] ?>&nbsp;/&nbsp;<?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'] ?>&nbsp;/&nbsp;<?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