From aa157bfd78c0704bf9c11b419cff44bc1f5c9317 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 11 Oct 2020 09:56:35 -0400 Subject: [PATCH 001/290] AddManufacturerId and ModelId to Monitors --- db/manufacturers.sql | 24 ++++++++++++++++++++ db/zm_create.sql.in | 2 ++ db/zm_update-1.35.10.sql | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 db/manufacturers.sql create mode 100644 db/zm_update-1.35.10.sql diff --git a/db/manufacturers.sql b/db/manufacturers.sql new file mode 100644 index 000000000..be15f9c01 --- /dev/null +++ b/db/manufacturers.sql @@ -0,0 +1,24 @@ +INSERT INTO Manufacturers VALUES (1, 'Acti'); +INSERT INTO Manufacturers VALUES (2, 'Amcrest'); +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 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'); diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index af6a17182..af4e37136 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -441,6 +441,8 @@ 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', diff --git a/db/zm_update-1.35.10.sql b/db/zm_update-1.35.10.sql new file mode 100644 index 000000000..341c5e162 --- /dev/null +++ b/db/zm_update-1.35.10.sql @@ -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; From a6de3e15f4eb0e9bed6682a6521f26a3b2c77947 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 11 Oct 2020 09:57:08 -0400 Subject: [PATCH 002/290] AddManufacturerId and ModelId to Monitor view --- web/skins/classic/views/monitor.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index d64880dff..13ec55633 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -462,7 +462,9 @@ if ( $tab != 'general' ) { ?> - + + + GroupIds() as $group_id ) { @@ -627,6 +629,24 @@ switch ( $tab ) { + + + ManufacturerId(), array('class'=>'chosen')); +?> + + + + + $monitor->ManufacturerId())); +echo htmlSelect('newMonitor[ModelId]', $models, $monitor->ModelId(), array('class'=>'chosen')); +?> + + Date: Sun, 11 Oct 2020 09:57:51 -0400 Subject: [PATCH 003/290] Add object classes for Manufacturer and Model --- web/includes/Manufacturer.php | 23 +++++++++++++++++++++++ web/includes/Model.php | 22 ++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 web/includes/Manufacturer.php create mode 100644 web/includes/Model.php diff --git a/web/includes/Manufacturer.php b/web/includes/Manufacturer.php new file mode 100644 index 000000000..73c46ad6b --- /dev/null +++ b/web/includes/Manufacturer.php @@ -0,0 +1,23 @@ + 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 +?> diff --git a/web/includes/Model.php b/web/includes/Model.php new file mode 100644 index 000000000..c9b22db8c --- /dev/null +++ b/web/includes/Model.php @@ -0,0 +1,22 @@ + 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 Model +?> From cc486beed50d12a1513db8d8312af4edfe825bb4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:45:23 -0400 Subject: [PATCH 004/290] Add some Acti models --- db/manufacturers.sql | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/db/manufacturers.sql b/db/manufacturers.sql index be15f9c01..eaee2630c 100644 --- a/db/manufacturers.sql +++ b/db/manufacturers.sql @@ -1,4 +1,23 @@ INSERT INTO Manufacturers VALUES (1, 'Acti'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A21'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A23'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A24'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A28'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A31'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A310'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A311'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A32'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A41'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A415'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A416'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A418'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A42'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A421'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A43'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A45'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A46'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A48'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A74'); INSERT INTO Manufacturers VALUES (2, 'Amcrest'); INSERT INTO Manufacturers VALUES (3, 'Airlink101'); INSERT INTO Manufacturers VALUES (4, 'Arecont Vision'); From 8df915e7a47c0b739d0ac39e3e5e7d2dff55d973 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:45:53 -0400 Subject: [PATCH 005/290] Fix merge. --- db/zm_update-1.35.29.sql | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/db/zm_update-1.35.29.sql b/db/zm_update-1.35.29.sql index 9030e5863..341c5e162 100644 --- a/db/zm_update-1.35.29.sql +++ b/db/zm_update-1.35.29.sql @@ -1,4 +1,3 @@ -<<<<<<< HEAD SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() AND table_name = 'Monitors' @@ -42,19 +41,6 @@ SET @s = (SELECT IF( ) > 0, "SELECT 'FOREIGN KEY for ModelId already exists in Monitors'", "ALTER TABLE `Monitors` ADD FOREIGN KEY (`ModelId`) REFERENCES `Models` (Id)" -======= --- --- Add AutoUnarchive action to Filters --- - -SET @s = (SELECT IF( - (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() - AND table_name = 'Filters' - AND column_name = 'AutoUnarchive' - ) > 0, -"SELECT 'Column AutoUunarchive already exists in Filters'", -"ALTER TABLE Filters ADD `AutoUnarchive` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoArchive`" ->>>>>>> master )); PREPARE stmt FROM @s; From 24a77d7fb365768c200559cc3353343e2b57a8e6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:46:12 -0400 Subject: [PATCH 006/290] Add ManufacturerId to Model --- web/includes/Model.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/includes/Model.php b/web/includes/Model.php index c9b22db8c..35562f9f9 100644 --- a/web/includes/Model.php +++ b/web/includes/Model.php @@ -9,6 +9,7 @@ class Model extends ZM_Object { protected $defaults = array( 'Id' => null, 'Name' => '', + 'ManufacturerId' => null, ); public static function find( $parameters = array(), $options = array() ) { From 3bb2b804b3a69f158e54149dc9e707a96cd611b0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:46:36 -0400 Subject: [PATCH 007/290] Include Model and Manufacturer to includes in Monitor.php --- web/includes/Monitor.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index ad3e95a0d..4f9450a3d 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -1,11 +1,13 @@ AlarmCommand('disable'); } + function Model() { + if (!$this->{'Model'}) { + $this->{'Model'} = Model::find_one(array('Id'=>$this->ModelId())); + if (!$this->{'Model'}) $this->{'Model'} = new Model(); + } + return $this->{'Model'}; + } + function Manufacturer() { + if (!$this->{'Manufacturer'}) { + $this->{'Manufacturer'} = Manufacturer::find_one(array('Id'=>$this->ManufacturerId())); + if (!$this->{'Manufacturer'}) $this->{'Manufacturer'} = new Manufacturer(); + } + return $this->{'Manufacturer'}; + } } // end class Monitor ?> From c6209ce460e4b942d42e9c0a84c10e6f06f38ab5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:47:00 -0400 Subject: [PATCH 008/290] Store new Model and Manufacturer when saving Monitor --- web/includes/actions/monitor.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/web/includes/actions/monitor.php b/web/includes/actions/monitor.php index 1c6e1f72f..3fafb0f82 100644 --- a/web/includes/actions/monitor.php +++ b/web/includes/actions/monitor.php @@ -45,6 +45,25 @@ if ( $action == 'save' ) { $x10Monitor = array(); } } + if ( !$_REQUEST['newMonitor[ManufacturerId'] and ($_REQUEST['newMonitor[Manufacturer'] != '') ) { + # Need to add a new Manufacturer entry + $newManufacturer = ZM\Manufacturer::find_one(array('Name'=>$_REQUEST['newMonitor[Manufacturer'])); + if (!$newManufacturer) { + $newManufacturer = new ZM\Manufacturer(); + $newManufacturer->save(array('Name'=>$_REQUEST['newMonitor[Manufacturer'])); + } + $_REQUEST['newMonitor[ManufacturerId'] = $newManufacturer->Id(); + } + + if ( !$_REQUEST['newMonitor[ModelId'] and ($_REQUEST['newMonitor[Model'] != '') ) { + # Need to add a new Model entry + $newModel = ZM\Model::find_one(array('Name'=>$_REQUEST['newMonitor[Model'])); + if (!$newModel) { + $newModel = new ZM\Model(); + $newMdoel->save(array('Name'=>$_REQUEST['newMonitor[Model'], 'ManufacturerId'=>$_REQUEST['newMonitor[ManufacturerId'])); + } + $_REQUEST['newMonitor[ModelId'] = $newModel->Id(); + } $monitor = new ZM\Monitor($mid); From 54f676a501b63bec148b2e951011b50bd0ae1592 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:47:32 -0400 Subject: [PATCH 009/290] Add ManufacturerId_onchange and ModelId_onchange to hide/show the text input for custom entry --- web/skins/classic/views/js/monitor.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/monitor.js b/web/skins/classic/views/js/monitor.js index 4b41d8dd2..d28d21bf5 100644 --- a/web/skins/classic/views/js/monitor.js +++ b/web/skins/classic/views/js/monitor.js @@ -323,7 +323,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'; @@ -345,4 +344,17 @@ function getLocation() { } } +function ManufacturerId_onchange(ManufacturerId_select) { + if (ManufacturerId_select.value()) + $j('newMonitor[Manufacturer]').hide(); + else + $j('newMonitor[Manufacturer]').show(); +} +function ModelId_onchange(ModelId_select) { + if (ModelId_select.value()) + $j('newMonitor[Model]').hide(); + else + $j('newMonitor[Model]').show(); +} + window.addEventListener('DOMContentLoaded', initPage); From 4ff4e1f7807d650b009384758487527ffc8c7ec5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:47:55 -0400 Subject: [PATCH 010/290] add Manufacturer and Model dropdown/text inputs to monitor edit view --- web/skins/classic/views/monitor.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 5e30db969..e6645dec5 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -492,18 +492,25 @@ switch ( $name ) { ManufacturerId(), array('class'=>'chosen')); +$manufacturers = array_merge( + array(''=>translate('unknown')), + ZM\Manufacturer::find()); +echo htmlSelect('newMonitor[ManufacturerId]', $manufacturers, $monitor->ManufacturerId(), array('class'=>'chosen','data-on-change-this'=>'ManufacturerId_onchange')); ?> + $monitor->ManufacturerId())); -echo htmlSelect('newMonitor[ModelId]', $models, $monitor->ModelId(), array('class'=>'chosen')); +$models = array_merge( + array(''=>translate('unknown')), + ZM\Model::find(array('ManufacturerId'=>$monitor->ManufacturerId())) +); +echo htmlSelect('newMonitor[ModelId]', $models, $monitor->ModelId(), array('class'=>'chosen', 'data-on-change-this'=>'ModelId_onchange')); ?> + From 413ac984eb3e1f496b38c08eecfda3104e56e8f3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jul 2021 09:48:24 -0400 Subject: [PATCH 011/290] add models.sql --- db/models.sql | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 db/models.sql diff --git a/db/models.sql b/db/models.sql new file mode 100644 index 000000000..b7150d816 --- /dev/null +++ b/db/models.sql @@ -0,0 +1,45 @@ +/* INSERT INTO Manufacturers VALUES (1, 'Acti'); */ +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A21'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A23'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A24'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A28'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A31'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A310'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A311'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A32'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A41'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A415'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A416'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A418'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A42'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A421'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A43'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A45'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A46'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A48'); +INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A74'); +/* +INSERT INTO Manufacturers VALUES (2, 'Amcrest'); +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 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'); +*/ From 7ca7d40b6fb94333c6d06a11f03aaf632b8c96cc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 10:32:04 -0400 Subject: [PATCH 012/290] Add defaults for ModelId and ManufacturerId. Fixes the methods for loading them --- web/includes/Monitor.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 54bf605cb..bd9987b2c 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -49,6 +49,8 @@ class Monitor extends ZM_Object { 'Notes' => '', 'ServerId' => 0, 'StorageId' => 0, + 'ManufacturerId' => null, + 'ModelId' => null, 'Type' => 'Ffmpeg', 'Function' => 'Mocord', 'Enabled' => array('type'=>'boolean','default'=>1), @@ -685,16 +687,26 @@ class Monitor extends ZM_Object { $output = $this->AlarmCommand('disable'); } function Model() { - if (!$this->{'Model'}) { - $this->{'Model'} = Model::find_one(array('Id'=>$this->ModelId())); - if (!$this->{'Model'}) $this->{'Model'} = new 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 (!$this->{'Manufacturer'}) { - $this->{'Manufacturer'} = Manufacturer::find_one(array('Id'=>$this->ManufacturerId())); - if (!$this->{'Manufacturer'}) $this->{'Manufacturer'} = new 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'}; } From 2f12615f088f8026bba909cb16e874947c353d9c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 10:33:16 -0400 Subject: [PATCH 013/290] assign REQUEST['newMonitor'] to a variable to simplify code. Fixup ModelId and ManufacturerId saving. --- web/includes/actions/monitor.php | 68 +++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/web/includes/actions/monitor.php b/web/includes/actions/monitor.php index 3fafb0f82..f6cbeca5f 100644 --- a/web/includes/actions/monitor.php +++ b/web/includes/actions/monitor.php @@ -45,24 +45,31 @@ if ( $action == 'save' ) { $x10Monitor = array(); } } - if ( !$_REQUEST['newMonitor[ManufacturerId'] and ($_REQUEST['newMonitor[Manufacturer'] != '') ) { + + # For convenience + $newMonitor = $_REQUEST['newMonitor']; + + if ( !$newMonitor['ManufacturerId'] and ($newMonitor['Manufacturer'] != '') ) { # Need to add a new Manufacturer entry - $newManufacturer = ZM\Manufacturer::find_one(array('Name'=>$_REQUEST['newMonitor[Manufacturer'])); + $newManufacturer = ZM\Manufacturer::find_one(array('Name'=>$newMonitor['Manufacturer'])); if (!$newManufacturer) { $newManufacturer = new ZM\Manufacturer(); - $newManufacturer->save(array('Name'=>$_REQUEST['newMonitor[Manufacturer'])); + $newManufacturer->save(array('Name'=>$newMonitor['Manufacturer'])); } - $_REQUEST['newMonitor[ManufacturerId'] = $newManufacturer->Id(); + $newMonitor['ManufacturerId'] = $newManufacturer->Id(); } - if ( !$_REQUEST['newMonitor[ModelId'] and ($_REQUEST['newMonitor[Model'] != '') ) { + if ( !$newMonitor['ModelId'] and ($newMonitor['Model'] != '') ) { # Need to add a new Model entry - $newModel = ZM\Model::find_one(array('Name'=>$_REQUEST['newMonitor[Model'])); + $newModel = ZM\Model::find_one(array('Name'=>$newMonitor['Model'])); if (!$newModel) { $newModel = new ZM\Model(); - $newMdoel->save(array('Name'=>$_REQUEST['newMonitor[Model'], 'ManufacturerId'=>$_REQUEST['newMonitor[ManufacturerId'])); + $newModel->save(array( + 'Name'=>$newMonitor['Model'], + 'ManufacturerId'=>$newMonitor['ManufacturerId'] + )); } - $_REQUEST['newMonitor[ModelId'] = $newModel->Id(); + $newMonitor['ModelId'] = $newModel->Id(); } $monitor = new ZM\Monitor($mid); @@ -88,22 +95,22 @@ 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; + 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']); + $changes = $monitor->changes($newMonitor); $restart = false; if ( count($changes) ) { @@ -134,13 +141,13 @@ if ( $action == 'save' ) { if ( file_exists($OldStorage->Path().'/'.$saferOldName) ) unlink($OldStorage->Path().'/'.$saferOldName); - $NewStorage = new ZM\Storage($_REQUEST['newMonitor']['StorageId']); + $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) ) { @@ -151,8 +158,8 @@ if ( $action == 'save' ) { } // end if Name or Storage Area Change if ( isset($changes['Width']) || isset($changes['Height']) ) { - $newW = $_REQUEST['newMonitor']['Width']; - $newH = $_REQUEST['newMonitor']['Height']; + $newW = $newMonitor['Width']; + $newH = $newMonitor['Height']; $zones = dbFetchAll('SELECT * FROM Zones WHERE MonitorId=?', NULL, array($mid)); @@ -236,14 +243,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 { From 12783f6edfe71dee6b8bf8a92e2c4fcf71404297 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 20:43:53 -0400 Subject: [PATCH 014/290] Add manufacturers, models and servers routes --- web/api/app/Config/routes.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/api/app/Config/routes.php b/web/api/app/Config/routes.php index 8dd2c1f63..6b3314d09 100644 --- a/web/api/app/Config/routes.php +++ b/web/api/app/Config/routes.php @@ -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,10 @@ Router::mapResources('groups'); Router::mapResources('host'); Router::mapResources('logs'); + Router::mapResources('manufacturers'); + Router::mapResources('models'); Router::mapResources('monitors'); + Router::mapResources('servers'); Router::mapResources('states'); Router::mapResources('users'); Router::mapResources('zonepresets'); From 34d9f87d6dee2916f7ada7edb7f4ef791c1fbe62 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 20:44:16 -0400 Subject: [PATCH 015/290] remove cruft from ServersController.php --- web/api/app/Controller/ServersController.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/web/api/app/Controller/ServersController.php b/web/api/app/Controller/ServersController.php index c3ac6fad7..bbde27fae 100644 --- a/web/api/app/Controller/ServersController.php +++ b/web/api/app/Controller/ServersController.php @@ -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 { From fe72056d73d84f527437c09dfdfd1c68841a4c47 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 20:48:14 -0400 Subject: [PATCH 016/290] fixup populating Models dropdown after Manufacturer select --- web/skins/classic/views/js/monitor.js | 53 ++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/web/skins/classic/views/js/monitor.js b/web/skins/classic/views/js/monitor.js index c32b66a0b..44bcddb5b 100644 --- a/web/skins/classic/views/js/monitor.js +++ b/web/skins/classic/views/js/monitor.js @@ -345,17 +345,52 @@ function getLocation() { } } -function ManufacturerId_onchange(ManufacturerId_select) { - if (ManufacturerId_select.value()) - $j('newMonitor[Manufacturer]').hide(); - else - $j('newMonitor[Manufacturer]').show(); +function populate_models(ManufacturerId) { + let dropdown = $j('[name="newMonitor[ModelId]"]'); + if (!dropdown.length) { + console.log("No element found for ModelId"); + return; + } + + dropdown.empty(); + dropdown.append(''); + dropdown.prop('selectedIndex', 0); + + // 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('').attr('value', entry.Id).text(entry.Name)); + }); + dropdown.chosen("destroy"); + dropdown.chosen(); + } else { + alert(data.result); + } + }); } + +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 + let ModelId_dropdown = $j('[name="newMonitor[ModelId]"]'); + ModelId_dropdown.empty(); + ModelId_dropdown.append(''); + ModelId_dropdown.prop('selectedIndex', 0); + $j('[name="newMonitor[Model]"]').show(); + } +} + function ModelId_onchange(ModelId_select) { - if (ModelId_select.value()) - $j('newMonitor[Model]').hide(); - else - $j('newMonitor[Model]').show(); + if (parseInt(ModelId_select.value)) { + $j('[name="newMonitor[Model]"]').hide(); + } else { + $j('[name="newMonitor[Model]"]').show(); + } } window.addEventListener('DOMContentLoaded', initPage); From d98d20958ce11244d0775b3b987c51b11ee662dc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 20:48:43 -0400 Subject: [PATCH 017/290] fixup the Manufacturer and Model ddms and text inputs --- web/skins/classic/views/monitor.php | 40 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index fa4b3ba4f..327de5def 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -457,27 +457,37 @@ switch ( $name ) { - translate('unknown')), - ZM\Manufacturer::find()); -echo htmlSelect('newMonitor[ManufacturerId]', $manufacturers, $monitor->ManufacturerId(), array('class'=>'chosen','data-on-change-this'=>'ManufacturerId_onchange')); + +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')); ?> - + ManufacturerId() ? ' style="display:none"' : '' ?> + /> - translate('unknown')), - ZM\Model::find(array('ManufacturerId'=>$monitor->ManufacturerId())) -); -echo htmlSelect('newMonitor[ModelId]', $models, $monitor->ModelId(), array('class'=>'chosen', 'data-on-change-this'=>'ModelId_onchange')); + +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')); ?> - + ModelId() ? ' style="display:none"':'' ?>/> From c66489fb303de460fac00c33aeb659f84635db49 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 20:49:30 -0400 Subject: [PATCH 018/290] rough in api support for Models and Manufacturers --- .../app/Controller/CameraModelsController.php | 156 +++++++++++++++++ .../Controller/ManufacturersController.php | 162 ++++++++++++++++++ web/api/app/Model/CameraModel.php | 70 ++++++++ web/api/app/Model/Manufacturer.php | 77 +++++++++ web/api/app/View/Manufacturers/json/edit.ctp | 2 + web/api/app/View/Manufacturers/json/index.ctp | 1 + web/api/app/View/Manufacturers/json/view.ctp | 1 + web/api/app/View/Manufacturers/xml/edit.ctp | 2 + web/api/app/View/Manufacturers/xml/index.ctp | 2 + web/api/app/View/Manufacturers/xml/view.ctp | 2 + 10 files changed, 475 insertions(+) create mode 100644 web/api/app/Controller/CameraModelsController.php create mode 100644 web/api/app/Controller/ManufacturersController.php create mode 100644 web/api/app/Model/CameraModel.php create mode 100644 web/api/app/Model/Manufacturer.php create mode 100644 web/api/app/View/Manufacturers/json/edit.ctp create mode 100644 web/api/app/View/Manufacturers/json/index.ctp create mode 100644 web/api/app/View/Manufacturers/json/view.ctp create mode 100644 web/api/app/View/Manufacturers/xml/edit.ctp create mode 100644 web/api/app/View/Manufacturers/xml/index.ctp create mode 100644 web/api/app/View/Manufacturers/xml/view.ctp diff --git a/web/api/app/Controller/CameraModelsController.php b/web/api/app/Controller/CameraModelsController.php new file mode 100644 index 000000000..691fd0767 --- /dev/null +++ b/web/api/app/Controller/CameraModelsController.php @@ -0,0 +1,156 @@ +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')); + } + } +} diff --git a/web/api/app/Controller/ManufacturersController.php b/web/api/app/Controller/ManufacturersController.php new file mode 100644 index 000000000..0249af6af --- /dev/null +++ b/web/api/app/Controller/ManufacturersController.php @@ -0,0 +1,162 @@ +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')); + } + } +} diff --git a/web/api/app/Model/CameraModel.php b/web/api/app/Model/CameraModel.php new file mode 100644 index 000000000..e953b5db8 --- /dev/null +++ b/web/api/app/Model/CameraModel.php @@ -0,0 +1,70 @@ + 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' ); +} diff --git a/web/api/app/Model/Manufacturer.php b/web/api/app/Model/Manufacturer.php new file mode 100644 index 000000000..34a6c88c0 --- /dev/null +++ b/web/api/app/Model/Manufacturer.php @@ -0,0 +1,77 @@ + 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' => '' + ) + ); +} diff --git a/web/api/app/View/Manufacturers/json/edit.ctp b/web/api/app/View/Manufacturers/json/edit.ctp new file mode 100644 index 000000000..a32d9cfad --- /dev/null +++ b/web/api/app/View/Manufacturers/json/edit.ctp @@ -0,0 +1,2 @@ +echo json_encode($message); +echo json_encode($manufacturer); diff --git a/web/api/app/View/Manufacturers/json/index.ctp b/web/api/app/View/Manufacturers/json/index.ctp new file mode 100644 index 000000000..4c54bdf95 --- /dev/null +++ b/web/api/app/View/Manufacturers/json/index.ctp @@ -0,0 +1 @@ +echo json_encode($manufacturers); diff --git a/web/api/app/View/Manufacturers/json/view.ctp b/web/api/app/View/Manufacturers/json/view.ctp new file mode 100644 index 000000000..4e0a14ae6 --- /dev/null +++ b/web/api/app/View/Manufacturers/json/view.ctp @@ -0,0 +1 @@ +echo json_encode($manufacturer); diff --git a/web/api/app/View/Manufacturers/xml/edit.ctp b/web/api/app/View/Manufacturers/xml/edit.ctp new file mode 100644 index 000000000..09fb8979a --- /dev/null +++ b/web/api/app/View/Manufacturers/xml/edit.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $message)); +echo $xml->asXML(); diff --git a/web/api/app/View/Manufacturers/xml/index.ctp b/web/api/app/View/Manufacturers/xml/index.ctp new file mode 100644 index 000000000..9bb514fff --- /dev/null +++ b/web/api/app/View/Manufacturers/xml/index.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $servers)); +echo $xml->asXML(); diff --git a/web/api/app/View/Manufacturers/xml/view.ctp b/web/api/app/View/Manufacturers/xml/view.ctp new file mode 100644 index 000000000..3b2a3fdad --- /dev/null +++ b/web/api/app/View/Manufacturers/xml/view.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $server)); +echo $xml->asXML(); From 292b3c1d3767fb9c57ccc2778f20d9e269c31754 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 20:49:53 -0400 Subject: [PATCH 019/290] add an ajax request for querying the available models --- web/ajax/models.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 web/ajax/models.php diff --git a/web/ajax/models.php b/web/ajax/models.php new file mode 100644 index 000000000..3a4f54c5b --- /dev/null +++ b/web/ajax/models.php @@ -0,0 +1,24 @@ +$_REQUEST['ManufacturerId']), array('order'=>'lower(Name)')); +ajaxResponse(array('models'=>$models)); +?> From 93c5ad0939df10685fe6042a7c8c13a0cf17213f Mon Sep 17 00:00:00 2001 From: Peter Keresztes Schmidt Date: Sun, 12 Sep 2021 11:28:57 +0200 Subject: [PATCH 020/290] Image: Fix Wclobbered warnings From C99 spec: [...] objects of automatic storage duration that are local to the function containing the invocation of the corresponding setjmp macro that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate Remove the variables in question or pass them as const refs. --- src/zm_image.cpp | 104 +++++++++++++++++++++++------------------------ src/zm_image.h | 2 +- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index a837138bc..f0d94a542 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -935,14 +935,13 @@ bool Image::WriteRaw(const char *filename) const { bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsigned int p_subpixelorder) { unsigned int new_width, new_height, new_colours, new_subpixelorder; - struct jpeg_decompress_struct *cinfo = readjpg_dcinfo; - if ( !cinfo ) { - cinfo = readjpg_dcinfo = new jpeg_decompress_struct; - cinfo->err = jpeg_std_error(&jpg_err.pub); + if ( !readjpg_dcinfo ) { + readjpg_dcinfo = new jpeg_decompress_struct; + readjpg_dcinfo->err = jpeg_std_error(&jpg_err.pub); jpg_err.pub.error_exit = zm_jpeg_error_exit; jpg_err.pub.emit_message = zm_jpeg_emit_message; - jpeg_create_decompress(cinfo); + jpeg_create_decompress(readjpg_dcinfo); } FILE *infile; @@ -952,30 +951,30 @@ bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsign } if ( setjmp(jpg_err.setjmp_buffer) ) { - jpeg_abort_decompress(cinfo); + jpeg_abort_decompress(readjpg_dcinfo); fclose(infile); return false; } - jpeg_stdio_src(cinfo, infile); + jpeg_stdio_src(readjpg_dcinfo, infile); - jpeg_read_header(cinfo, TRUE); + jpeg_read_header(readjpg_dcinfo, TRUE); - if ( (cinfo->num_components != 1) && (cinfo->num_components != 3) ) { + if ( (readjpg_dcinfo->num_components != 1) && (readjpg_dcinfo->num_components != 3) ) { Error("Unexpected colours when reading jpeg image: %d", colours); - jpeg_abort_decompress(cinfo); + jpeg_abort_decompress(readjpg_dcinfo); fclose(infile); return false; } /* Check if the image has at least one huffman table defined. If not, use the standard ones */ /* This is required for the MJPEG capture palette of USB devices */ - if ( cinfo->dc_huff_tbl_ptrs[0] == nullptr ) { - zm_use_std_huff_tables(cinfo); + if ( readjpg_dcinfo->dc_huff_tbl_ptrs[0] == nullptr ) { + zm_use_std_huff_tables(readjpg_dcinfo); } - new_width = cinfo->image_width; - new_height = cinfo->image_height; + new_width = readjpg_dcinfo->image_width; + new_height = readjpg_dcinfo->image_height; if ( (width != new_width) || (height != new_height) ) { Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", width, height, new_width, new_height); @@ -983,7 +982,7 @@ bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsign switch ( p_colours ) { case ZM_COLOUR_GRAY8: - cinfo->out_color_space = JCS_GRAYSCALE; + readjpg_dcinfo->out_color_space = JCS_GRAYSCALE; new_colours = ZM_COLOUR_GRAY8; new_subpixelorder = ZM_SUBPIX_ORDER_NONE; break; @@ -991,17 +990,17 @@ bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsign #ifdef JCS_EXTENSIONS new_colours = ZM_COLOUR_RGB32; if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGRA ) { - cinfo->out_color_space = JCS_EXT_BGRX; + readjpg_dcinfo->out_color_space = JCS_EXT_BGRX; new_subpixelorder = ZM_SUBPIX_ORDER_BGRA; } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ARGB ) { - cinfo->out_color_space = JCS_EXT_XRGB; + readjpg_dcinfo->out_color_space = JCS_EXT_XRGB; new_subpixelorder = ZM_SUBPIX_ORDER_ARGB; } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ABGR ) { - cinfo->out_color_space = JCS_EXT_XBGR; + readjpg_dcinfo->out_color_space = JCS_EXT_XBGR; new_subpixelorder = ZM_SUBPIX_ORDER_ABGR; } else { /* Assume RGBA */ - cinfo->out_color_space = JCS_EXT_RGBX; + readjpg_dcinfo->out_color_space = JCS_EXT_RGBX; new_subpixelorder = ZM_SUBPIX_ORDER_RGBA; } break; @@ -1013,7 +1012,7 @@ bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsign new_colours = ZM_COLOUR_RGB24; if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGR ) { #ifdef JCS_EXTENSIONS - cinfo->out_color_space = JCS_EXT_BGR; + readjpg_dcinfo->out_color_space = JCS_EXT_BGR; new_subpixelorder = ZM_SUBPIX_ORDER_BGR; #else Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); @@ -1029,7 +1028,7 @@ cinfo->out_color_space = JCS_EXT_RGB; cinfo->out_color_space = JCS_RGB; #endif */ - cinfo->out_color_space = JCS_RGB; + readjpg_dcinfo->out_color_space = JCS_RGB; new_subpixelorder = ZM_SUBPIX_ORDER_RGB; } break; @@ -1037,20 +1036,20 @@ cinfo->out_color_space = JCS_RGB; if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr ) { Error("Failed requesting writeable buffer for reading JPEG image."); - jpeg_abort_decompress(cinfo); + jpeg_abort_decompress(readjpg_dcinfo); fclose(infile); return false; } - jpeg_start_decompress(cinfo); + jpeg_start_decompress(readjpg_dcinfo); JSAMPROW row_pointer = buffer; - while ( cinfo->output_scanline < cinfo->output_height ) { - jpeg_read_scanlines(cinfo, &row_pointer, 1); + while ( readjpg_dcinfo->output_scanline < readjpg_dcinfo->output_height ) { + jpeg_read_scanlines(readjpg_dcinfo, &row_pointer, 1); row_pointer += linesize; } - jpeg_finish_decompress(cinfo); + jpeg_finish_decompress(readjpg_dcinfo); fclose(infile); @@ -1078,7 +1077,7 @@ bool Image::WriteJpeg(const std::string &filename, int quality_override, SystemT } bool Image::WriteJpeg(const std::string &filename, - int quality_override, + const int &quality_override, SystemTimePoint timestamp, bool on_blocking_abort) const { if ( config.colour_jpeg_files && (colours == ZM_COLOUR_GRAY8) ) { @@ -1247,39 +1246,38 @@ bool Image::DecodeJpeg( unsigned int p_subpixelorder) { unsigned int new_width, new_height, new_colours, new_subpixelorder; - struct jpeg_decompress_struct *cinfo = decodejpg_dcinfo; - if ( !cinfo ) { - cinfo = decodejpg_dcinfo = new jpeg_decompress_struct; - cinfo->err = jpeg_std_error( &jpg_err.pub ); + if ( !decodejpg_dcinfo ) { + decodejpg_dcinfo = new jpeg_decompress_struct; + decodejpg_dcinfo->err = jpeg_std_error( &jpg_err.pub ); jpg_err.pub.error_exit = zm_jpeg_error_exit; jpg_err.pub.emit_message = zm_jpeg_emit_message; - jpeg_create_decompress( cinfo ); + jpeg_create_decompress( decodejpg_dcinfo ); } if ( setjmp(jpg_err.setjmp_buffer) ) { - jpeg_abort_decompress(cinfo); + jpeg_abort_decompress(decodejpg_dcinfo); return false; } - zm_jpeg_mem_src(cinfo, inbuffer, inbuffer_size); + zm_jpeg_mem_src(decodejpg_dcinfo, inbuffer, inbuffer_size); - jpeg_read_header(cinfo, TRUE); + jpeg_read_header(decodejpg_dcinfo, TRUE); - if ( (cinfo->num_components != 1) && (cinfo->num_components != 3) ) { + if ( (decodejpg_dcinfo->num_components != 1) && (decodejpg_dcinfo->num_components != 3) ) { Error("Unexpected colours when reading jpeg image: %d", colours); - jpeg_abort_decompress(cinfo); + jpeg_abort_decompress(decodejpg_dcinfo); return false; } /* Check if the image has at least one huffman table defined. If not, use the standard ones */ /* This is required for the MJPEG capture palette of USB devices */ - if ( cinfo->dc_huff_tbl_ptrs[0] == nullptr ) { - zm_use_std_huff_tables(cinfo); + if ( decodejpg_dcinfo->dc_huff_tbl_ptrs[0] == nullptr ) { + zm_use_std_huff_tables(decodejpg_dcinfo); } - new_width = cinfo->image_width; - new_height = cinfo->image_height; + new_width = decodejpg_dcinfo->image_width; + new_height = decodejpg_dcinfo->image_height; if ( (width != new_width) || (height != new_height) ) { Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", @@ -1288,7 +1286,7 @@ bool Image::DecodeJpeg( switch (p_colours) { case ZM_COLOUR_GRAY8: - cinfo->out_color_space = JCS_GRAYSCALE; + decodejpg_dcinfo->out_color_space = JCS_GRAYSCALE; new_colours = ZM_COLOUR_GRAY8; new_subpixelorder = ZM_SUBPIX_ORDER_NONE; break; @@ -1296,17 +1294,17 @@ bool Image::DecodeJpeg( #ifdef JCS_EXTENSIONS new_colours = ZM_COLOUR_RGB32; if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGRA ) { - cinfo->out_color_space = JCS_EXT_BGRX; + decodejpg_dcinfo->out_color_space = JCS_EXT_BGRX; new_subpixelorder = ZM_SUBPIX_ORDER_BGRA; } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ARGB ) { - cinfo->out_color_space = JCS_EXT_XRGB; + decodejpg_dcinfo->out_color_space = JCS_EXT_XRGB; new_subpixelorder = ZM_SUBPIX_ORDER_ARGB; } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ABGR ) { - cinfo->out_color_space = JCS_EXT_XBGR; + decodejpg_dcinfo->out_color_space = JCS_EXT_XBGR; new_subpixelorder = ZM_SUBPIX_ORDER_ABGR; } else { /* Assume RGBA */ - cinfo->out_color_space = JCS_EXT_RGBX; + decodejpg_dcinfo->out_color_space = JCS_EXT_RGBX; new_subpixelorder = ZM_SUBPIX_ORDER_RGBA; } break; @@ -1318,7 +1316,7 @@ bool Image::DecodeJpeg( new_colours = ZM_COLOUR_RGB24; if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGR ) { #ifdef JCS_EXTENSIONS - cinfo->out_color_space = JCS_EXT_BGR; + decodejpg_dcinfo->out_color_space = JCS_EXT_BGR; new_subpixelorder = ZM_SUBPIX_ORDER_BGR; #else Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); @@ -1334,7 +1332,7 @@ cinfo->out_color_space = JCS_EXT_RGB; cinfo->out_color_space = JCS_RGB; #endif */ - cinfo->out_color_space = JCS_RGB; + decodejpg_dcinfo->out_color_space = JCS_RGB; new_subpixelorder = ZM_SUBPIX_ORDER_RGB; } break; @@ -1342,19 +1340,19 @@ cinfo->out_color_space = JCS_RGB; if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr ) { Error("Failed requesting writeable buffer for reading JPEG image."); - jpeg_abort_decompress(cinfo); + jpeg_abort_decompress(decodejpg_dcinfo); return false; } - jpeg_start_decompress(cinfo); + jpeg_start_decompress(decodejpg_dcinfo); JSAMPROW row_pointer = buffer; /* pointer to a single row */ - while ( cinfo->output_scanline < cinfo->output_height ) { - jpeg_read_scanlines(cinfo, &row_pointer, 1); + while ( decodejpg_dcinfo->output_scanline < decodejpg_dcinfo->output_height ) { + jpeg_read_scanlines(decodejpg_dcinfo, &row_pointer, 1); row_pointer += linesize; } - jpeg_finish_decompress(cinfo); + jpeg_finish_decompress(decodejpg_dcinfo); return true; } diff --git a/src/zm_image.h b/src/zm_image.h index 7778747e4..ccbae9f86 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -241,7 +241,7 @@ class Image { bool WriteJpeg(const std::string &filename, SystemTimePoint timestamp) const; bool WriteJpeg(const std::string &filename, int quality_override, SystemTimePoint timestamp) const; bool WriteJpeg(const std::string &filename, - int quality_override, + const int &quality_override, SystemTimePoint timestamp, bool on_blocking_abort) const; From a4ebf533a93e8834b24455541a48735a6dcbf20e Mon Sep 17 00:00:00 2001 From: Peter Keresztes Schmidt Date: Sun, 12 Sep 2021 11:38:44 +0200 Subject: [PATCH 021/290] Image: Codestyle changes --- src/zm_image.cpp | 304 +++++++++++++++++++++++------------------------ 1 file changed, 151 insertions(+), 153 deletions(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index f0d94a542..09c05550e 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -936,7 +936,7 @@ bool Image::WriteRaw(const char *filename) const { bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsigned int p_subpixelorder) { unsigned int new_width, new_height, new_colours, new_subpixelorder; - if ( !readjpg_dcinfo ) { + if (!readjpg_dcinfo) { readjpg_dcinfo = new jpeg_decompress_struct; readjpg_dcinfo->err = jpeg_std_error(&jpg_err.pub); jpg_err.pub.error_exit = zm_jpeg_error_exit; @@ -945,12 +945,12 @@ bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsign } FILE *infile; - if ( (infile = fopen(filename.c_str(), "rb")) == nullptr ) { + if ((infile = fopen(filename.c_str(), "rb")) == nullptr) { Error("Can't open %s: %s", filename.c_str(), strerror(errno)); return false; } - if ( setjmp(jpg_err.setjmp_buffer) ) { + if (setjmp(jpg_err.setjmp_buffer)) { jpeg_abort_decompress(readjpg_dcinfo); fclose(infile); return false; @@ -958,9 +958,9 @@ bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsign jpeg_stdio_src(readjpg_dcinfo, infile); - jpeg_read_header(readjpg_dcinfo, TRUE); + jpeg_read_header(readjpg_dcinfo, true); - if ( (readjpg_dcinfo->num_components != 1) && (readjpg_dcinfo->num_components != 3) ) { + if ((readjpg_dcinfo->num_components != 1) && (readjpg_dcinfo->num_components != 3)) { Error("Unexpected colours when reading jpeg image: %d", colours); jpeg_abort_decompress(readjpg_dcinfo); fclose(infile); @@ -969,72 +969,72 @@ bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsign /* Check if the image has at least one huffman table defined. If not, use the standard ones */ /* This is required for the MJPEG capture palette of USB devices */ - if ( readjpg_dcinfo->dc_huff_tbl_ptrs[0] == nullptr ) { + if (readjpg_dcinfo->dc_huff_tbl_ptrs[0] == nullptr) { zm_use_std_huff_tables(readjpg_dcinfo); } new_width = readjpg_dcinfo->image_width; new_height = readjpg_dcinfo->image_height; - if ( (width != new_width) || (height != new_height) ) { + if ((width != new_width) || (height != new_height)) { Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", width, height, new_width, new_height); } - switch ( p_colours ) { + switch (p_colours) { case ZM_COLOUR_GRAY8: - readjpg_dcinfo->out_color_space = JCS_GRAYSCALE; - new_colours = ZM_COLOUR_GRAY8; - new_subpixelorder = ZM_SUBPIX_ORDER_NONE; - break; + readjpg_dcinfo->out_color_space = JCS_GRAYSCALE; + new_colours = ZM_COLOUR_GRAY8; + new_subpixelorder = ZM_SUBPIX_ORDER_NONE; + break; case ZM_COLOUR_RGB32: #ifdef JCS_EXTENSIONS - new_colours = ZM_COLOUR_RGB32; - if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGRA ) { - readjpg_dcinfo->out_color_space = JCS_EXT_BGRX; - new_subpixelorder = ZM_SUBPIX_ORDER_BGRA; - } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ARGB ) { - readjpg_dcinfo->out_color_space = JCS_EXT_XRGB; - new_subpixelorder = ZM_SUBPIX_ORDER_ARGB; - } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ABGR ) { - readjpg_dcinfo->out_color_space = JCS_EXT_XBGR; - new_subpixelorder = ZM_SUBPIX_ORDER_ABGR; - } else { - /* Assume RGBA */ - readjpg_dcinfo->out_color_space = JCS_EXT_RGBX; - new_subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } - break; + new_colours = ZM_COLOUR_RGB32; + if (p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) { + readjpg_dcinfo->out_color_space = JCS_EXT_BGRX; + new_subpixelorder = ZM_SUBPIX_ORDER_BGRA; + } else if (p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) { + readjpg_dcinfo->out_color_space = JCS_EXT_XRGB; + new_subpixelorder = ZM_SUBPIX_ORDER_ARGB; + } else if (p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) { + readjpg_dcinfo->out_color_space = JCS_EXT_XBGR; + new_subpixelorder = ZM_SUBPIX_ORDER_ABGR; + } else { + /* Assume RGBA */ + readjpg_dcinfo->out_color_space = JCS_EXT_RGBX; + new_subpixelorder = ZM_SUBPIX_ORDER_RGBA; + } + break; #else - Warning("libjpeg-turbo is required for reading a JPEG directly into a RGB32 buffer, reading into a RGB24 buffer instead."); + Warning("libjpeg-turbo is required for reading a JPEG directly into a RGB32 buffer, reading into a RGB24 buffer instead."); #endif case ZM_COLOUR_RGB24: default: - new_colours = ZM_COLOUR_RGB24; - if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGR ) { + new_colours = ZM_COLOUR_RGB24; + if (p_subpixelorder == ZM_SUBPIX_ORDER_BGR) { #ifdef JCS_EXTENSIONS - readjpg_dcinfo->out_color_space = JCS_EXT_BGR; - new_subpixelorder = ZM_SUBPIX_ORDER_BGR; + readjpg_dcinfo->out_color_space = JCS_EXT_BGR; + new_subpixelorder = ZM_SUBPIX_ORDER_BGR; #else - Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); - cinfo->out_color_space = JCS_RGB; - new_subpixelorder = ZM_SUBPIX_ORDER_RGB; + Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); + cinfo->out_color_space = JCS_RGB; + new_subpixelorder = ZM_SUBPIX_ORDER_RGB; #endif - } else { - /* Assume RGB */ - /* + } else { + /* Assume RGB */ + /* #ifdef JCS_EXTENSIONS cinfo->out_color_space = JCS_EXT_RGB; #else cinfo->out_color_space = JCS_RGB; #endif - */ - readjpg_dcinfo->out_color_space = JCS_RGB; - new_subpixelorder = ZM_SUBPIX_ORDER_RGB; - } - break; + */ + readjpg_dcinfo->out_color_space = JCS_RGB; + new_subpixelorder = ZM_SUBPIX_ORDER_RGB; + } + break; } // end switch p_colours - if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr ) { + if (WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr) { Error("Failed requesting writeable buffer for reading JPEG image."); jpeg_abort_decompress(readjpg_dcinfo); fclose(infile); @@ -1044,13 +1044,12 @@ cinfo->out_color_space = JCS_RGB; jpeg_start_decompress(readjpg_dcinfo); JSAMPROW row_pointer = buffer; - while ( readjpg_dcinfo->output_scanline < readjpg_dcinfo->output_height ) { + while (readjpg_dcinfo->output_scanline < readjpg_dcinfo->output_height) { jpeg_read_scanlines(readjpg_dcinfo, &row_pointer, 1); row_pointer += linesize; } jpeg_finish_decompress(readjpg_dcinfo); - fclose(infile); return true; @@ -1080,34 +1079,37 @@ bool Image::WriteJpeg(const std::string &filename, const int &quality_override, SystemTimePoint timestamp, bool on_blocking_abort) const { - if ( config.colour_jpeg_files && (colours == ZM_COLOUR_GRAY8) ) { + if (config.colour_jpeg_files && (colours == ZM_COLOUR_GRAY8)) { Image temp_image(*this); temp_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB); return temp_image.WriteJpeg(filename, quality_override, timestamp, on_blocking_abort); } int quality = quality_override ? quality_override : config.jpeg_file_quality; - struct jpeg_compress_struct *cinfo = writejpg_ccinfo[quality]; + jpeg_compress_struct *cinfo = writejpg_ccinfo[quality]; FILE *outfile = nullptr; int raw_fd = 0; - if ( !cinfo ) { + if (!cinfo) { cinfo = writejpg_ccinfo[quality] = new jpeg_compress_struct; cinfo->err = jpeg_std_error(&jpg_err.pub); jpeg_create_compress(cinfo); } - if ( !on_blocking_abort ) { + if (!on_blocking_abort) { jpg_err.pub.error_exit = zm_jpeg_error_exit; jpg_err.pub.emit_message = zm_jpeg_emit_message; } else { jpg_err.pub.error_exit = zm_jpeg_error_silent; jpg_err.pub.emit_message = zm_jpeg_emit_silence; - if ( setjmp(jpg_err.setjmp_buffer) ) { + if (setjmp(jpg_err.setjmp_buffer)) { jpeg_abort_compress(cinfo); - Debug(1, "Aborted a write mid-stream and %s and %d", (outfile == nullptr) ? "closing file" : "file not opened", raw_fd); - if ( raw_fd ) + Debug(1, + "Aborted a write mid-stream and %s and %d", + (outfile == nullptr) ? "closing file" : "file not opened", + raw_fd); + if (raw_fd) close(raw_fd); - if ( outfile ) + if (outfile) fclose(outfile); return false; } @@ -1134,58 +1136,58 @@ bool Image::WriteJpeg(const std::string &filename, cinfo->image_width = width; /* image width and height, in pixels */ cinfo->image_height = height; - switch ( colours ) { + switch (colours) { case ZM_COLOUR_GRAY8: - cinfo->input_components = 1; - cinfo->in_color_space = JCS_GRAYSCALE; - break; + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + break; case ZM_COLOUR_RGB32: #ifdef JCS_EXTENSIONS - cinfo->input_components = 4; - if ( subpixelorder == ZM_SUBPIX_ORDER_RGBA ) { - cinfo->in_color_space = JCS_EXT_RGBX; - } else if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) { - cinfo->in_color_space = JCS_EXT_BGRX; - } else if ( subpixelorder == ZM_SUBPIX_ORDER_ARGB ) { - cinfo->in_color_space = JCS_EXT_XRGB; - } else if ( subpixelorder == ZM_SUBPIX_ORDER_ABGR ) { - cinfo->in_color_space = JCS_EXT_XBGR; - } else { - Warning("Unknwon subpixelorder %d", subpixelorder); - /* Assume RGBA */ - cinfo->in_color_space = JCS_EXT_RGBX; - } - break; + cinfo->input_components = 4; + if (subpixelorder == ZM_SUBPIX_ORDER_RGBA) { + cinfo->in_color_space = JCS_EXT_RGBX; + } else if (subpixelorder == ZM_SUBPIX_ORDER_BGRA) { + cinfo->in_color_space = JCS_EXT_BGRX; + } else if (subpixelorder == ZM_SUBPIX_ORDER_ARGB) { + cinfo->in_color_space = JCS_EXT_XRGB; + } else if (subpixelorder == ZM_SUBPIX_ORDER_ABGR) { + cinfo->in_color_space = JCS_EXT_XBGR; + } else { + Warning("Unknwon subpixelorder %d", subpixelorder); + /* Assume RGBA */ + cinfo->in_color_space = JCS_EXT_RGBX; + } + break; #else - Error("libjpeg-turbo is required for JPEG encoding directly from RGB32 source"); + Error("libjpeg-turbo is required for JPEG encoding directly from RGB32 source"); + jpeg_abort_compress(cinfo); + fclose(outfile); + return false; +#endif + case ZM_COLOUR_RGB24: + default: + cinfo->input_components = 3; + if (subpixelorder == ZM_SUBPIX_ORDER_BGR) { +#ifdef JCS_EXTENSIONS + cinfo->in_color_space = JCS_EXT_BGR; +#else + Error("libjpeg-turbo is required for JPEG encoding directly from BGR24 source"); jpeg_abort_compress(cinfo); fclose(outfile); return false; #endif - case ZM_COLOUR_RGB24: - default: - cinfo->input_components = 3; - if ( subpixelorder == ZM_SUBPIX_ORDER_BGR) { -#ifdef JCS_EXTENSIONS - cinfo->in_color_space = JCS_EXT_BGR; -#else - Error("libjpeg-turbo is required for JPEG encoding directly from BGR24 source"); - jpeg_abort_compress(cinfo); - fclose(outfile); - return false; -#endif - } else { - /* Assume RGB */ - /* + } else { + /* Assume RGB */ + /* #ifdef JCS_EXTENSIONS cinfo->out_color_space = JCS_EXT_RGB; #else cinfo->out_color_space = JCS_RGB; #endif */ - cinfo->in_color_space = JCS_RGB; - } - break; + cinfo->in_color_space = JCS_RGB; + } + break; } // end switch(colours) jpeg_set_defaults(cinfo); @@ -1193,7 +1195,7 @@ cinfo->out_color_space = JCS_RGB; cinfo->dct_method = JDCT_FASTEST; jpeg_start_compress(cinfo, TRUE); - if ( config.add_jpeg_comments && !annotation_.empty() ) { + if (config.add_jpeg_comments && !annotation_.empty()) { jpeg_write_marker(cinfo, JPEG_COM, reinterpret_cast(annotation_.c_str()), annotation_.size()); } // If we have a non-zero time (meaning a parameter was passed in), then form a simple exif segment with that time as DateTimeOriginal and SubsecTimeOriginal @@ -1217,19 +1219,19 @@ cinfo->out_color_space = JCS_RGB; snprintf(msbuf, sizeof msbuf, "%06d", static_cast(ts_usec.count())); unsigned char exiftimes[82] = { - 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x69, 0x87, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x03, 0x90, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x91, 0x92, - 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00 }; - memcpy(&exiftimes[EXIFTIMES_OFFSET], timebuf,EXIFTIMES_LEN); + 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x69, 0x87, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x03, 0x90, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x91, 0x92, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00}; + memcpy(&exiftimes[EXIFTIMES_OFFSET], timebuf, EXIFTIMES_LEN); memcpy(&exiftimes[EXIFTIMES_MS_OFFSET], msbuf, EXIFTIMES_MS_LEN); - jpeg_write_marker(cinfo, EXIF_CODE, (const JOCTET *)exiftimes, sizeof(exiftimes)); + jpeg_write_marker(cinfo, EXIF_CODE, (const JOCTET *) exiftimes, sizeof(exiftimes)); } JSAMPROW row_pointer = buffer; /* pointer to a single row */ - while ( cinfo->next_scanline < cinfo->image_height ) { + while (cinfo->next_scanline < cinfo->image_height) { jpeg_write_scanlines(cinfo, &row_pointer, 1); row_pointer += linesize; } @@ -1239,23 +1241,19 @@ cinfo->out_color_space = JCS_RGB; return true; } -bool Image::DecodeJpeg( - const JOCTET *inbuffer, - int inbuffer_size, - unsigned int p_colours, - unsigned int p_subpixelorder) +bool Image::DecodeJpeg(const JOCTET *inbuffer, int inbuffer_size, unsigned int p_colours, unsigned int p_subpixelorder) { unsigned int new_width, new_height, new_colours, new_subpixelorder; - if ( !decodejpg_dcinfo ) { + if (!decodejpg_dcinfo) { decodejpg_dcinfo = new jpeg_decompress_struct; - decodejpg_dcinfo->err = jpeg_std_error( &jpg_err.pub ); + decodejpg_dcinfo->err = jpeg_std_error(&jpg_err.pub); jpg_err.pub.error_exit = zm_jpeg_error_exit; jpg_err.pub.emit_message = zm_jpeg_emit_message; - jpeg_create_decompress( decodejpg_dcinfo ); + jpeg_create_decompress(decodejpg_dcinfo); } - if ( setjmp(jpg_err.setjmp_buffer) ) { + if (setjmp(jpg_err.setjmp_buffer)) { jpeg_abort_decompress(decodejpg_dcinfo); return false; } @@ -1264,7 +1262,7 @@ bool Image::DecodeJpeg( jpeg_read_header(decodejpg_dcinfo, TRUE); - if ( (decodejpg_dcinfo->num_components != 1) && (decodejpg_dcinfo->num_components != 3) ) { + if ((decodejpg_dcinfo->num_components != 1) && (decodejpg_dcinfo->num_components != 3)) { Error("Unexpected colours when reading jpeg image: %d", colours); jpeg_abort_decompress(decodejpg_dcinfo); return false; @@ -1272,73 +1270,73 @@ bool Image::DecodeJpeg( /* Check if the image has at least one huffman table defined. If not, use the standard ones */ /* This is required for the MJPEG capture palette of USB devices */ - if ( decodejpg_dcinfo->dc_huff_tbl_ptrs[0] == nullptr ) { + if (decodejpg_dcinfo->dc_huff_tbl_ptrs[0] == nullptr) { zm_use_std_huff_tables(decodejpg_dcinfo); } new_width = decodejpg_dcinfo->image_width; new_height = decodejpg_dcinfo->image_height; - if ( (width != new_width) || (height != new_height) ) { + if ((width != new_width) || (height != new_height)) { Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", - width, height, new_width, new_height); + width, height, new_width, new_height); } switch (p_colours) { case ZM_COLOUR_GRAY8: decodejpg_dcinfo->out_color_space = JCS_GRAYSCALE; - new_colours = ZM_COLOUR_GRAY8; - new_subpixelorder = ZM_SUBPIX_ORDER_NONE; - break; + new_colours = ZM_COLOUR_GRAY8; + new_subpixelorder = ZM_SUBPIX_ORDER_NONE; + break; case ZM_COLOUR_RGB32: #ifdef JCS_EXTENSIONS - new_colours = ZM_COLOUR_RGB32; - if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGRA ) { - decodejpg_dcinfo->out_color_space = JCS_EXT_BGRX; - new_subpixelorder = ZM_SUBPIX_ORDER_BGRA; - } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ARGB ) { - decodejpg_dcinfo->out_color_space = JCS_EXT_XRGB; - new_subpixelorder = ZM_SUBPIX_ORDER_ARGB; - } else if ( p_subpixelorder == ZM_SUBPIX_ORDER_ABGR ) { - decodejpg_dcinfo->out_color_space = JCS_EXT_XBGR; - new_subpixelorder = ZM_SUBPIX_ORDER_ABGR; - } else { - /* Assume RGBA */ - decodejpg_dcinfo->out_color_space = JCS_EXT_RGBX; - new_subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } - break; + new_colours = ZM_COLOUR_RGB32; + if (p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) { + decodejpg_dcinfo->out_color_space = JCS_EXT_BGRX; + new_subpixelorder = ZM_SUBPIX_ORDER_BGRA; + } else if (p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) { + decodejpg_dcinfo->out_color_space = JCS_EXT_XRGB; + new_subpixelorder = ZM_SUBPIX_ORDER_ARGB; + } else if (p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) { + decodejpg_dcinfo->out_color_space = JCS_EXT_XBGR; + new_subpixelorder = ZM_SUBPIX_ORDER_ABGR; + } else { + /* Assume RGBA */ + decodejpg_dcinfo->out_color_space = JCS_EXT_RGBX; + new_subpixelorder = ZM_SUBPIX_ORDER_RGBA; + } + break; #else - Warning("libjpeg-turbo is required for reading a JPEG directly into a RGB32 buffer, reading into a RGB24 buffer instead."); + Warning("libjpeg-turbo is required for reading a JPEG directly into a RGB32 buffer, reading into a RGB24 buffer instead."); #endif case ZM_COLOUR_RGB24: default: - new_colours = ZM_COLOUR_RGB24; - if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGR ) { + new_colours = ZM_COLOUR_RGB24; + if (p_subpixelorder == ZM_SUBPIX_ORDER_BGR) { #ifdef JCS_EXTENSIONS - decodejpg_dcinfo->out_color_space = JCS_EXT_BGR; - new_subpixelorder = ZM_SUBPIX_ORDER_BGR; + decodejpg_dcinfo->out_color_space = JCS_EXT_BGR; + new_subpixelorder = ZM_SUBPIX_ORDER_BGR; #else - Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); - cinfo->out_color_space = JCS_RGB; - new_subpixelorder = ZM_SUBPIX_ORDER_RGB; + Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); + cinfo->out_color_space = JCS_RGB; + new_subpixelorder = ZM_SUBPIX_ORDER_RGB; #endif - } else { - /* Assume RGB */ - /* + } else { + /* Assume RGB */ + /* #ifdef JCS_EXTENSIONS cinfo->out_color_space = JCS_EXT_RGB; #else cinfo->out_color_space = JCS_RGB; #endif - */ - decodejpg_dcinfo->out_color_space = JCS_RGB; - new_subpixelorder = ZM_SUBPIX_ORDER_RGB; - } - break; + */ + decodejpg_dcinfo->out_color_space = JCS_RGB; + new_subpixelorder = ZM_SUBPIX_ORDER_RGB; + } + break; } // end switch - if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr ) { + if (WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr) { Error("Failed requesting writeable buffer for reading JPEG image."); jpeg_abort_decompress(decodejpg_dcinfo); return false; @@ -1347,7 +1345,7 @@ cinfo->out_color_space = JCS_RGB; jpeg_start_decompress(decodejpg_dcinfo); JSAMPROW row_pointer = buffer; /* pointer to a single row */ - while ( decodejpg_dcinfo->output_scanline < decodejpg_dcinfo->output_height ) { + while (decodejpg_dcinfo->output_scanline < decodejpg_dcinfo->output_height) { jpeg_read_scanlines(decodejpg_dcinfo, &row_pointer, 1); row_pointer += linesize; } From 4b4152b837f07eba1bcb0ce0dfadc23546d6c6f2 Mon Sep 17 00:00:00 2001 From: Andrea Vezzali Date: Mon, 13 Sep 2021 13:28:48 +0200 Subject: [PATCH 022/290] Update it_it translation (#3350) --- web/lang/it_it.php | 274 ++++++++++++++++++++++----------------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/web/lang/it_it.php b/web/lang/it_it.php index 62e881d45..b51b85300 100644 --- a/web/lang/it_it.php +++ b/web/lang/it_it.php @@ -98,8 +98,8 @@ $SLANG = array( 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Attenzione', 'All' => 'Tutto', - 'AnalysisFPS' => 'Analysis FPS', // Added - 2015-07-22 - 'AnalysisUpdateDelay' => 'Analysis Update Delay', // Added - 2015-07-23 + 'AnalysisFPS' => 'Analisi FPS', // Added - 2015-07-22 + 'AnalysisUpdateDelay' => 'Intervallo aggiornamento analisi', // Added - 2015-07-23 'Apply' => 'Applica', 'ApplyingStateChange' => 'Sto applicando le modifiche', 'ArchArchived' => 'Archiviato', @@ -112,31 +112,31 @@ $SLANG = array( 'AttrArchiveStatus' => 'Stato Archivio', 'AttrAvgScore' => 'Punteggio medio', 'AttrCause' => 'Causa', - 'AttrDiskBlocks' => 'Blocchi del Disco', - 'AttrDiskPercent' => 'Percentuale del Disco', - 'AttrDiskSpace' => 'Disk Space', // Added - 2018-08-30 + 'AttrDiskBlocks' => 'Blocchi disco', + 'AttrDiskPercent' => 'Percentuale disco', + 'AttrDiskSpace' => 'Spazio disco', // Added - 2018-08-30 'AttrDuration' => 'Durata', 'AttrEndDate' => 'End Date', // Added - 2018-08-30 'AttrEndDateTime' => 'End Date/Time', // Added - 2018-08-30 'AttrEndTime' => 'End Time', // Added - 2018-08-30 'AttrEndWeekday' => 'End Weekday', // Added - 2018-08-30 - 'AttrFilterServer' => 'Server Filter is Running On', // Added - 2018-08-30 + 'AttrFilterServer' => 'Filtro attivo su Server', // Added - 2018-08-30 'AttrFrames' => 'Immagini', 'AttrId' => 'Id', 'AttrMaxScore' => 'Punteggio massimo', 'AttrMonitorId' => 'Id Monitor', 'AttrMonitorName' => 'Nome Monitor', - 'AttrMonitorServer' => 'Server Monitor is Running On', // Added - 2018-08-30 + 'AttrMonitorServer' => 'Monitor attivo su Server', // Added - 2018-08-30 'AttrName' => 'Nome', 'AttrNotes' => 'Note', - 'AttrStartDate' => 'Start Date', // Added - 2018-08-30 - 'AttrStartDateTime' => 'Start Date/Time', // Added - 2018-08-30 - 'AttrStartTime' => 'Start Time', // Added - 2018-08-30 - 'AttrStartWeekday' => 'Start Weekday', // Added - 2018-08-30 - 'AttrStateId' => 'Run State', // Added - 2018-08-30 - 'AttrStorageArea' => 'Storage Area', // Added - 2018-08-30 - 'AttrStorageServer' => 'Server Hosting Storage', // Added - 2018-08-30 - 'AttrSystemLoad' => 'System Load', + 'AttrStartDate' => 'Inizio - Data', // Added - 2018-08-30 + 'AttrStartDateTime' => 'Inizio - Data/orario', // Added - 2018-08-30 + 'AttrStartTime' => 'Inizio - Orario', // Added - 2018-08-30 + 'AttrStartWeekday' => 'Inizio - Giorno della settimana', // Added - 2018-08-30 + 'AttrStateId' => 'Stato esecuzione', // Added - 2018-08-30 + 'AttrStorageArea' => 'Area Salvataggio', // Added - 2018-08-30 + 'AttrStorageServer' => 'Server Salvataggio remoto', // Added - 2018-08-30 + 'AttrSystemLoad' => 'Carico di sistema', 'AttrTotalScore' => 'Punteggio totale', 'Auto' => 'Auto', 'AutoStopTimeout' => 'Auto Stop Timeout', @@ -181,56 +181,56 @@ $SLANG = array( 'BlobPx' => 'Blob Px', 'BlobSizes' => 'Dimensioni Blob', 'Blobs' => 'Blobs', - 'Brightness' => 'Luminosità', + 'Brightness' => 'Luminosità;', 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffers', 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 - 'CanAutoFocus' => 'Puo\' Auto Focus', - 'CanAutoGain' => 'Puo\' Auto Gains', - 'CanAutoIris' => 'Puo\' Auto Iris', - 'CanAutoWhite' => 'Puo\' Auto bil bianco', - 'CanAutoZoom' => 'Puo\' Auto Zoom', - 'CanFocus' => 'Puo\' Fuoco', - 'CanFocusAbs' => 'Puo\' Fuoco Assoluto', - 'CanFocusCon' => 'Puo\' Fuoco Continuo ', - 'CanFocusRel' => 'Puo\' Fuoco Relativo', - 'CanGain' => 'Puo\' Gain ', - 'CanGainAbs' => 'Puo\' Gain Assoluto', - 'CanGainCon' => 'Puo\' Gain Continuo ', - 'CanGainRel' => 'Puo\' Gain Relativo', - 'CanIris' => 'Puo\' Iris', - 'CanIrisAbs' => 'Puo\' Iris Assoluto', - 'CanIrisCon' => 'Puo\' Iris Continuo ', - 'CanIrisRel' => 'Puo\' Iris Relativo', - 'CanMove' => 'Puo\' Mov.', - 'CanMoveAbs' => 'Puo\' Mov. Assoluto', - 'CanMoveCon' => 'Puo\' Mov. Continuo ', - 'CanMoveDiag' => 'Puo\' Mov. Diagonale ', - 'CanMoveMap' => 'Puo\' Mov Mappato', - 'CanMoveRel' => 'Puo\' Mov. Relativo', - 'CanPan' => 'Puo\' Pan' , - 'CanReset' => 'Puo\' Reset', - 'CanReboot' => 'Can Reboot', - 'CanSetPresets' => 'Puo\' impostare preset', - 'CanSleep' => 'Puo\' andare in sleep', - 'CanTilt' => 'Puo\' Tilt', - 'CanWake' => 'Puo\' essere riattivato', - 'CanWhite' => 'Puo\' bilanciare il bianco', - 'CanWhiteAbs' => 'Puo\' bilanciare il bianco assoluto', - 'CanWhiteBal' => 'Puo\' bilanciare il bianco', - 'CanWhiteCon' => 'Puo\' bilanciare il bianco Continuo', - 'CanWhiteRel' => 'Puo\' bilanciare il bianco Relativo', - 'CanZoom' => 'Puo\' Zoom', - 'CanZoomAbs' => 'Puo\' Zoom Assoluto', - 'CanZoomCon' => 'Puo\' Zoom Continuo', - 'CanZoomRel' => 'Puo\' Zoom Relativo', + 'CanAutoFocus' => 'Può Auto Focus', + 'CanAutoGain' => 'Può Auto Gains', + 'CanAutoIris' => 'Può Auto Iris', + 'CanAutoWhite' => 'Può Auto bil bianco', + 'CanAutoZoom' => 'Può Auto Zoom', + 'CanFocus' => 'Può Fuoco', + 'CanFocusAbs' => 'Può Fuoco Assoluto', + 'CanFocusCon' => 'Può Fuoco Continuo ', + 'CanFocusRel' => 'Può Fuoco Relativo', + 'CanGain' => 'Può Gain ', + 'CanGainAbs' => 'Può Gain Assoluto', + 'CanGainCon' => 'Può Gain Continuo ', + 'CanGainRel' => 'Può Gain Relativo', + 'CanIris' => 'Può Iris', + 'CanIrisAbs' => 'Può Iris Assoluto', + 'CanIrisCon' => 'Può Iris Continuo ', + 'CanIrisRel' => 'Può Iris Relativo', + 'CanMove' => 'Può Mov.', + 'CanMoveAbs' => 'Può Mov. Assoluto', + 'CanMoveCon' => 'Può Mov. Continuo ', + 'CanMoveDiag' => 'Può Mov. Diagonale ', + 'CanMoveMap' => 'Può Mov Mappato', + 'CanMoveRel' => 'Può Mov. Relativo', + 'CanPan' => 'Può Pan' , + 'CanReset' => 'Può Reset', + 'CanReboot' => 'Può Riavviare', + 'CanSetPresets' => 'Può impostare preset', + 'CanSleep' => 'Può andare in sleep', + 'CanTilt' => 'Può Tilt', + 'CanWake' => 'Può essere riattivato', + 'CanWhite' => 'Può bilanciare il bianco', + 'CanWhiteAbs' => 'Può bilanciare il bianco assoluto', + 'CanWhiteBal' => 'Può bilanciare il bianco', + 'CanWhiteCon' => 'Può bilanciare il bianco Continuo', + 'CanWhiteRel' => 'Può bilanciare il bianco Relativo', + 'CanZoom' => 'Può Zoom', + 'CanZoomAbs' => 'Può Zoom Assoluto', + 'CanZoomCon' => 'Può Zoom Continuo', + 'CanZoomRel' => 'Può Zoom Relativo', 'Cancel' => 'Annulla', 'CancelForcedAlarm' => 'Annulla Allarme Forzato', - 'CaptureHeight' => 'Altezza img catturata', - 'CaptureMethod' => 'Metodo di cattura', // Added - 2009-02-08 - 'CapturePalette' => 'Paletta img catturata', - 'CaptureResolution' => 'Risoluzione di cattura', // Added - 2015-04-18 - 'CaptureWidth' => 'Larghezza img Catturata', + 'CaptureHeight' => 'Altezza Cattura Immagine', + 'CaptureMethod' => 'Metodo Cattura Immagine', // Added - 2009-02-08 + 'CapturePalette' => 'Tavolozza Cattura Immagine', + 'CaptureResolution' => 'Risoluzione Cattura Immagine', // Added - 2015-04-18 + 'CaptureWidth' => 'Larghezza Cattura Immagine', 'Cause' => 'Causa', 'CheckMethod' => 'Metodo di Controllo Allarme', 'ChooseDetectedCamera' => 'Scegli telecamera rilevata', // Added - 2009-03-31 @@ -244,7 +244,7 @@ $SLANG = array( 'Colour' => 'Colori', 'Command' => 'Comando', 'Component' => 'Component', // Added - 2011-06-16 - 'ConcurrentFilter' => 'Run filter concurrently', // Added - 2018-08-30 + 'ConcurrentFilter' => 'Esegui filtro contemporaneamente', // Added - 2018-08-30 'Config' => 'Configura', 'ConfiguredFor' => 'Configurato per', 'ConfirmDeleteEvents' => 'Sei sicuro di voler cancellare gli eventi selezionati', @@ -279,7 +279,7 @@ $SLANG = array( 'DeleteSavedFilter' => 'Elimina il filtro salvato', 'Description' => 'Descrizione', 'DetectedCameras' => 'Telecamere Rilevate', // Added - 2009-03-31 - 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 + 'DetectedProfiles' => 'Profili Rilevati', // Added - 2015-04-18 'Device' => 'Periferica', // Added - 2009-02-08 'DeviceChannel' => 'Canale Periferica', 'DeviceFormat' => 'Formato', @@ -287,14 +287,14 @@ $SLANG = array( 'DevicePath' => 'Percorso Dispositivo', 'Devices' => 'Dispositivi', 'Dimensions' => 'Dimensioni', - 'DisableAlarms' => 'Disabil Allarme', + 'DisableAlarms' => 'Disabilita Allarme', 'Disk' => 'Utilizzo Disco', - 'Display' => 'Display', // Added - 2011-01-30 - 'Displaying' => 'Displaying', // Added - 2011-06-16 - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', + 'Display' => 'Mostra', // Added - 2011-01-30 + 'Displaying' => 'Visualizzazione', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Attiva Motion Detection Nativo', 'Donate' => 'Donate,per favore', 'DonateAlready' => 'No, ho gia donato... ', - 'DonateEnticement' => 'Stai usando ZoneMinder da un po\' di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.

Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a https://zoneminder.com/donate/ .

Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.', + 'DonateEnticement' => 'Stai usando ZoneMinder da un pò di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.

Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a https://zoneminder.com/donate/ .

Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.', 'DonateRemindDay' => 'Non ancora, ricordamelo ancora tra 1 giorno', 'DonateRemindHour' => 'Non ancora, ricordamelo ancora tra 1 ora', 'DonateRemindMonth' => 'Non ancora, ricordamelo ancora tra 1 mese', @@ -325,24 +325,24 @@ $SLANG = array( 'Execute' => 'Esegui', 'Exif' => 'Includi dati EXIF nell\'immagine', // Added - 2018-08-30 'Export' => 'Esporta', - 'ExportDetails' => 'Esp. dettagli eventi', - 'ExportFailed' => 'Esp. Fallita ', - 'ExportFormat' => 'Formato File Esp. ', + 'ExportDetails' => 'Esporta dettagli eventi', + 'ExportFailed' => 'Esportazione Fallita ', + 'ExportFormat' => 'Formato File Esportazione', 'ExportFormatTar' => 'Tar', 'ExportFormatZip' => 'Zip', - 'ExportFrames' => 'Dettagli frame espo.', + 'ExportFrames' => 'Esporta dettagli immagini', 'ExportImageFiles' => 'Esporta le immagini', - 'ExportLog' => 'Export Log', // Added - 2011-06-17 - 'ExportMiscFiles' => 'Esporto Altri file (se presenti)', + 'ExportLog' => 'Esporta Log', // Added - 2011-06-17 + 'ExportMiscFiles' => 'Esporta Altri file (se presenti)', 'ExportOptions' => 'Opzioni Esportazione', - 'ExportSucceeded' => 'Export completata con successo', // Added - 2009-02-08 - 'ExportVideoFiles' => 'Esporto File Video (se presenti)', - 'Exporting' => 'In corso.', + 'ExportSucceeded' => 'Esportazione completata con successo', // Added - 2009-02-08 + 'ExportVideoFiles' => 'Esporta File Video (se presenti)', + 'Exporting' => 'In corso', 'FPS' => 'fps', 'FPSReportInterval' => 'Intervallo Report FPS', 'FTP' => 'FTP', 'Far' => 'Lontano', - 'FastForward' => 'Fast Forward', + 'FastForward' => 'Avanzamento veloce', 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', @@ -351,7 +351,7 @@ $SLANG = array( 'FilterDeleteEvents' => 'Elimina gli eventi', 'FilterEmailEvents' => 'Invia dettagli via email', 'FilterExecuteEvents' => 'Esegui un comando', - 'FilterLog' => 'Filter log', // Added - 2015-04-18 + 'FilterLog' => 'Filtra log', // Added - 2015-04-18 'FilterMessageEvents' => 'Invia dettagli tramite messaggio', 'FilterMoveEvents' => 'Sposta tutti gli eventi', // Added - 2018-08-30 'FilterPx' => 'Px Filtro', @@ -388,19 +388,19 @@ $SLANG = array( 'Grey' => 'Grigio', 'Group' => 'Gruppo', 'Groups' => 'Gruppi', - 'HasFocusSpeed' => 'Ha velocita\' di focus', - 'HasGainSpeed' => 'Ha velocita\' di guadagno', + 'HasFocusSpeed' => 'Ha velocità di focus', + 'HasGainSpeed' => 'Ha velocità di guadagno', 'HasHomePreset' => 'Ha posizioni di present', - 'HasIrisSpeed' => 'Ha velocota\' di iris', - 'HasPanSpeed' => 'Ha velocita\' di Pan', + 'HasIrisSpeed' => 'Ha velocotà di iris', + 'HasPanSpeed' => 'Ha velocità di Pan', 'HasPresets' => 'Ha preset', - 'HasTiltSpeed' => 'Ha velocita\' di Tilt', + 'HasTiltSpeed' => 'Ha velocità di Tilt', 'HasTurboPan' => 'Ha il Turbo Pan', 'HasTurboTilt' => 'Ha il Turbo Tilt', - 'HasWhiteSpeed' => 'Ha velocita\' di bilanciamento del bianco', - 'HasZoomSpeed' => 'Ha velocita\' di zoom', + 'HasWhiteSpeed' => 'Ha velocità di bilanciamento del bianco', + 'HasZoomSpeed' => 'Ha velocità di zoom', 'High' => 'Alta', - 'HighBW' => 'Banda Alta', + 'HighBW' => 'Banda Alta', 'Home' => 'Home', 'Hostname' => 'Nome Host', // Added - 2018-08-30 'Hour' => 'Ora', @@ -445,31 +445,31 @@ $SLANG = array( 'Mark' => 'Seleziona', 'Max' => 'Massima', 'MaxBandwidth' => 'Banda Massima', - 'MaxBrScore' => 'Punteggio
Massimo', + 'MaxBrScore' => 'Punteggio Massimo', 'MaxFocusRange' => 'Massimo range del focus', - 'MaxFocusSpeed' => 'Massima velocita\' del focus', + 'MaxFocusSpeed' => 'Massima velocità del focus', 'MaxFocusStep' => 'Massimo step del focus', 'MaxGainRange' => 'Massimo range del guadagno', - 'MaxGainSpeed' => 'Massima velocita\' del guadagno', + 'MaxGainSpeed' => 'Massima velocità del guadagno', 'MaxGainStep' => 'Massimo step del guadagno', 'MaxIrisRange' => 'Massima range dell\'Iris', - 'MaxIrisSpeed' => 'Massima velocita\' dell\'Iris', + 'MaxIrisSpeed' => 'Massima velocità dell\'Iris', 'MaxIrisStep' => 'Massimo step dell\'Iris', 'MaxPanRange' => 'Massimo range del pan', - 'MaxPanSpeed' => 'Massima velocita\' del tilt', + 'MaxPanSpeed' => 'Massima velocità del tilt', 'MaxPanStep' => 'Massimo step del pan', 'MaxTiltRange' => 'Massimo range del tilt', - 'MaxTiltSpeed' => 'Massima velocita\' del tilt', + 'MaxTiltSpeed' => 'Massima velocità del tilt', 'MaxTiltStep' => 'Massimo passo del tilt', 'MaxWhiteRange' => 'Massimo range del bilanciamento del bianco', - 'MaxWhiteSpeed' => 'Massima velocita\' del bilanciamento del bianco', + 'MaxWhiteSpeed' => 'Massima velocità del bilanciamento del bianco', 'MaxWhiteStep' => 'Massimo Step del bilanciamento del bianco', 'MaxZoomRange' => 'Massimo range dello zoom', - 'MaxZoomSpeed' => 'Massima velocita\' dello zoom', + 'MaxZoomSpeed' => 'Massima velocità dello zoom', 'MaxZoomStep' => 'Massimo step dello zoom', 'MaximumFPS' => 'Massimi FPS', 'Medium' => 'Media', - 'MediumBW' => 'Banda Media', + 'MediumBW' => 'Larghezza Banda Media', 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'L\'area minima dell\'allarme deve essere minore di quella massima', 'MinAlarmAreaUnset' => 'Devi specificare il numero minimo di pixel per l\'allarme', @@ -482,47 +482,47 @@ $SLANG = array( 'MinFilterAreaUnset' => 'Devi specificare il numero minimo di pixel per il filtro', 'MinFilterLtMinAlarm' => 'L\'area minima di filtro deve essere minore o uguale dell\area minima di allarme', 'MinFocusRange' => 'Range minimo del Focus', - 'MinFocusSpeed' => 'Velocita\' minima del Focus', + 'MinFocusSpeed' => 'Velocità minima del Focus', 'MinFocusStep' => 'Minimo step del Focus', 'MinGainRange' => 'Minimo range del Guadagno', - 'MinGainSpeed' => 'Velocita\' minima del Guadagno', + 'MinGainSpeed' => 'Velocità minima del Guadagno', 'MinGainStep' => 'Step minimo del guadagno', 'MinIrisRange' => 'Range minimo dell\'Iris', - 'MinIrisSpeed' => 'Velocita\' minima dell\'Iris', + 'MinIrisSpeed' => 'Velocità minima dell\'Iris', 'MinIrisStep' => 'Step minimo dell\'Iris', 'MinPanRange' => 'Range minimo del pan', - 'MinPanSpeed' => 'Velocita\' minima del Pan', + 'MinPanSpeed' => 'Velocità minima del Pan', 'MinPanStep' => 'Step minimo del Pan', 'MinPixelThresLtMax' => 'I pixel minimi della soglia devono essere minori dei pixel massimi della soglia', 'MinPixelThresUnset' => 'Devi specificare una soglia minima di pixel', // Added - 2009-02-08 'MinTiltRange' => 'Range minimo del Tilt', - 'MinTiltSpeed' => 'Velocita\' minima del Tilt', + 'MinTiltSpeed' => 'Velocità minima del Tilt', 'MinTiltStep' => 'Step minimo del Tilt', 'MinWhiteRange' => 'Range minimo del bilanciamento del bianco', - 'MinWhiteSpeed' => 'Velocita\' minima del bialnciamento del bianco', + 'MinWhiteSpeed' => 'Velocità minima del bialnciamento del bianco', 'MinWhiteStep' => 'Minimo step del bilanciamento del bianco', 'MinZoomRange' => 'Range minimo dello zoom', - 'MinZoomSpeed' => 'Velocita\' minima dello zoom', + 'MinZoomSpeed' => 'Velocità minima dello zoom', 'MinZoomStep' => 'Step minimo dello zoom', 'Misc' => 'Altro', 'Mode' => 'Modalità', // Added - 2015-04-18 'Monitor' => 'Monitor', - 'MonitorIds' => 'Monitor Ids', + 'MonitorIds' => 'Monitor Ids', 'MonitorPreset' => 'Monitor Presenti', 'MonitorPresetIntro' => 'Selezionare un appropriato pre settaggio dalla lista riportata qui sotto.

Per favore notare che questo potrebbe sovrascrivere ogni valore che hai già configurato su questo monitor.

', 'MonitorProbe' => 'Prova Monitor', // Added - 2009-03-31 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2009-03-31 'Monitors' => 'Monitors', 'Montage' => 'Montaggio', - 'MontageReview' => 'Montage Review', // Added - 2018-08-30 + 'MontageReview' => 'Revisione del montaggio', // Added - 2018-08-30 'Month' => 'Mese', - 'More' => 'More', // Added - 2011-06-16 - 'MotionFrameSkip' => 'Motion Frame Skip', + 'More' => 'Più', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Salta/scarta fotogramma', 'Move' => 'Sposta', - 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. - 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'Mtg2widgrd' => 'Griglia 2 colonne', // Added 2013.08.15. + 'Mtg3widgrd' => 'Griglia 3 colonne', // Added 2013.08.15. + 'Mtg3widgrx' => 'Griglia 3 colonne, scalata, ingrandita su allarme', // Added 2013.08.15. + 'Mtg4widgrd' => 'Griglia 4 colonne', // Added 2013.08.15. 'MtgDefault' => 'Predefinito', // Added 2013.08.15. 'MustBeGe' => 'deve essere superiore a', 'MustBeLe' => 'deve essere inferiore o pari a', @@ -609,7 +609,7 @@ $SLANG = array( 'ProfileProbeIntro' => 'L\'elenco seguente mostra i profili di streaming esistenti della telecamera selezionata.

Selezionare la voce desiderata dall\'elenco seguente.

Si noti che ZoneMinder non è in grado di configurare profili aggiuntivi e che la scelta di una telecamera qui può sovrascrivere qualsiasi valore già configurato per il monitor corrente.

', // Added - 2015-04-18 'Progress' => 'Progresso', // Added - 2015-04-18 'Protocol' => 'Protocollo', - 'RTSPDescribe' => 'Use RTSP Response Media URL', // Added - 2018-08-30 + 'RTSPDescribe' => 'Usa URL multimediale di risposta RTSP', // Added - 2018-08-30 'RTSPTransport' => 'RTSP Transport Protocol', // Added - 2018-08-30 'Rate' => 'Velocità', 'Real' => 'Reale', @@ -622,15 +622,15 @@ $SLANG = array( 'RemoteHostName' => 'Nome dell\'Host Remoto', 'RemoteHostPath' => 'Percorso dell\'Host Remoto', 'RemoteHostPort' => 'Porta dell\'Host Remoto', - 'RemoteHostSubPath' => 'SubPath host remoto', // Added - 2009-02-08 + 'RemoteHostSubPath' => 'Percorso secondario dell\'Host remoto', // Added - 2009-02-08 'RemoteImageColours' => 'Colori delle immagini Remote', 'RemoteMethod' => 'Metodo Remoto', // Added - 2009-02-08 'RemoteProtocol' => 'Protocollo Remoto', // Added - 2009-02-08 'Rename' => 'Rinomina', - 'Replay' => 'Replay', - 'ReplayAll' => 'All Events', - 'ReplayGapless' => 'Gapless Events', - 'ReplaySingle' => 'Single Event', + 'Replay' => 'Riproduci', + 'ReplayAll' => 'Tutti gli Eventi', + 'ReplayGapless' => 'Eventi continui', + 'ReplaySingle' => 'Evento singolo', 'ReportEventAudit' => 'Rapporto Eventi di controllo', // Added - 2018-08-30 'Reset' => 'Resetta', 'ResetEventCounts' => 'Resetta Contatore Eventi', @@ -644,7 +644,7 @@ $SLANG = array( 'RotateLeft' => 'Ruota a Sinista', 'RotateRight' => 'Ruota a Destra', 'RunLocalUpdate' => 'Eseguire zmupdate.pl per l\'aggiornamento', // Added - 2011-05-25 - 'RunMode' => 'Modalita\' funzionamento', + 'RunMode' => 'Modalità funzionamento', 'RunState' => 'Stato di funzionamento', 'Running' => 'Attivo', 'Save' => 'Salva', @@ -679,25 +679,25 @@ $SLANG = array( 'SourcePath' => 'Percorso della Sorgente', // Added - 2009-02-08 'SourceType' => 'Tipo Sorgente', 'Speed' => 'Velocita\'', - 'SpeedHigh' => 'Alta Velocita\'', - 'SpeedLow' => 'Bassa Velocita\'', - 'SpeedMedium' => 'Media Velocita\'', - 'SpeedTurbo' => 'Turbo Velocita\'', + 'SpeedHigh' => 'Alta Velocità', + 'SpeedLow' => 'Bassa Velocità', + 'SpeedMedium' => 'Media Velocità', + 'SpeedTurbo' => 'Turbo Velocità', 'Start' => 'Avvia', 'State' => 'Stato', 'Stats' => 'Statistiche', 'Status' => 'Stato', - 'StatusConnected' => 'Capturing', // Added - 2018-08-30 - 'StatusNotRunning' => 'Not Running', // Added - 2018-08-30 - 'StatusRunning' => 'Not Capturing', // Added - 2018-08-30 - 'StatusUnknown' => 'Unknown', // Added - 2018-08-30 + 'StatusConnected' => 'Registrazione in corso', // Added - 2018-08-30 + 'StatusNotRunning' => 'Non in esecuzione', // Added - 2018-08-30 + 'StatusRunning' => 'Registrazione in pausa', // Added - 2018-08-30 + 'StatusUnknown' => 'Sconosciuto', // Added - 2018-08-30 'Step' => 'Passo', 'StepBack' => 'Passo indietro', 'StepForward' => 'Passo avanti', - 'StepLarge' => 'Lungo passo', - 'StepMedium' => 'Medio passo', - 'StepNone' => 'No passo', - 'StepSmall' => 'Piccolo passo', + 'StepLarge' => 'Passo lungo', + 'StepMedium' => 'Passo medio', + 'StepNone' => 'Nessun passo', + 'StepSmall' => 'Passo piccolo', 'Stills' => 'Foto', 'Stop' => 'Stop', 'Stopped' => 'Inattivo', @@ -728,12 +728,12 @@ $SLANG = array( 'Today' => 'Oggi ', 'Tools' => 'Strumenti', 'Total' => 'Totale', // Added - 2011-06-16 - 'TotalBrScore' => 'Punteggio
Totale', + 'TotalBrScore' => 'Punteggio Totale', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', 'Triggers' => 'Triggers', - 'TurboPanSpeed' => 'Velocita\' Turbo Pan', - 'TurboTiltSpeed' => 'Velocita\' Turbo Tilt', + 'TurboPanSpeed' => 'Velocità Turbo Pan', + 'TurboTiltSpeed' => 'Velocità Turbo Tilt', 'Type' => 'Tipo', 'Unarchive' => 'Togli dall\'archivio', 'Undefined' => 'Non specificato', // Added - 2009-02-08 @@ -745,7 +745,7 @@ $SLANG = array( 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 'UseFilter' => 'Usa Filtro', - 'UseFilterExprsPost' => ' espressioni filtri', // This is used at the end of the phrase 'use N filter expressions' + 'UseFilterExprsPost' => ' espressioni filtri', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usa ', // This is used at the beginning of the phrase 'use N filter expressions' 'UsedPlugins' => 'Used Plugins', 'User' => 'Utente', @@ -767,7 +767,7 @@ $SLANG = array( 'VideoGenFiles' => 'File Video Esistenti', 'VideoGenNoFiles' => 'Non ho trovato file ', 'VideoGenParms' => 'Parametri Generazione Video', - 'VideoGenSucceeded' => 'Successo: Generato Video !', + 'VideoGenSucceeded' => 'Successo: Video Generato!', 'VideoSize' => 'Dimensioni Video', 'VideoWriter' => 'Scrittore video', // Added - 2018-08-30 'View' => 'Vedi', @@ -782,7 +782,7 @@ $SLANG = array( 'WebSiteUrl' => 'Website URL', // Added - 2018-08-30 'Week' => 'Settimana', 'White' => 'Bianco', - 'WhiteBalance' => 'Bil. Bianco ', + 'WhiteBalance' => 'Bilanciamento del Bianco', 'Wide' => 'Larghezza', 'X' => 'X', 'X10' => 'X10', @@ -795,7 +795,7 @@ $SLANG = array( 'Zone' => 'Zona', 'ZoneAlarmColour' => 'Colore Allarme (RGB)', 'ZoneArea' => 'Zone Area', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', + 'ZoneExtendAlarmFrames' => 'Estendi conteggio immagini allarme', 'ZoneFilterSize' => 'Larghezza/Altezza Filtro (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Area Allarmata', 'ZoneMinMaxBlobArea' => 'Min/Max Area di Blob', @@ -803,7 +803,7 @@ $SLANG = array( 'ZoneMinMaxFiltArea' => 'Min/Max Area Filtrata', 'ZoneMinMaxPixelThres' => 'Min/Max Soglia Pixel (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 - 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', + 'ZoneOverloadFrames' => 'Sovraccarico - contatore immagini ignorate', 'Zones' => 'Zone', 'Zoom' => 'Zoom', 'ZoomIn' => 'Ingrandisci', From 6dbfd2219076afb377381babb75ac6ec39ba5066 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Sep 2021 15:03:36 -0400 Subject: [PATCH 023/290] Add missing update_function_pointers so that we use SSE blend functions. Significantly reduces cpu use in motion detection. --- src/zm_image.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 09c05550e..2b7bc69e2 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -313,6 +313,7 @@ bool Image::Assign(const AVFrame *frame, SwsContext *convert_context, AVFrame *t return false; } zm_dump_video_frame(temp_frame, "dest frame after convert"); + update_function_pointers(); return true; } // end Image::Assign(const AVFrame *frame, SwsContext *convert_context, AVFrame *temp_frame) @@ -687,6 +688,7 @@ void Image::AssignDirect( subpixelorder = p_subpixelorder; pixels = width * height; size = new_buffer_size; + update_function_pointers(); } // end void Image::AssignDirect void Image::Assign( @@ -788,6 +790,7 @@ void Image::Assign(const Image &image) { linesize = image.linesize; } + update_function_pointers(); if ( image.buffer != buffer ) (*fptr_imgbufcpy)(buffer, image.buffer, size); } From c4a49721d2f77128a3e3404a1a22fbabd55a08d1 Mon Sep 17 00:00:00 2001 From: Andrea Vezzali Date: Tue, 14 Sep 2021 15:16:25 +0200 Subject: [PATCH 024/290] Update it_it.php --- web/lang/it_it.php | 140 ++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/web/lang/it_it.php b/web/lang/it_it.php index b51b85300..f06b18cc4 100644 --- a/web/lang/it_it.php +++ b/web/lang/it_it.php @@ -84,7 +84,7 @@ $SLANG = array( 'AddNewControl' => 'Aggiungi nuovo Controllo', 'AddNewMonitor' => 'Aggiungi nuovo Monitor', 'AddNewServer' => 'Aggiungi nuovo Server', // Added - 2018-08-30 - 'AddNewStorage' => 'Aggiungi nuovo Storage', // Added - 2018-08-30 + 'AddNewStorage' => 'Aggiungi nuovo Archivio', // Added - 2018-08-30 'AddNewUser' => 'Aggiungi nuovo Utente', 'AddNewZone' => 'Aggiungi nuova Zona', 'Alarm' => 'Allarme', @@ -95,7 +95,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'FPS massimi durante l\'allarme', 'AlarmPx' => 'Pixel Allarme', 'AlarmRGBUnset' => 'Devi settare un colore RGB di allarme', - 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 + 'AlarmRefImageBlendPct'=> 'Riferimento Allarme - Fusione Immagine %', // Added - 2015-04-18 'Alert' => 'Attenzione', 'All' => 'Tutto', 'AnalysisFPS' => 'Analisi FPS', // Added - 2015-07-22 @@ -103,14 +103,14 @@ $SLANG = array( 'Apply' => 'Applica', 'ApplyingStateChange' => 'Sto applicando le modifiche', 'ArchArchived' => 'Archiviato', - 'ArchUnarchived' => 'Non archiviato', + 'ArchUnarchived' => 'Non Archiviato', 'Archive' => 'Archivio', 'Archived' => 'Archiviato', 'Area' => 'Area', 'AreaUnits' => 'Area (px/%)', - 'AttrAlarmFrames' => 'Immagini in Allarme', + 'AttrAlarmFrames' => 'Immagini Allarme', 'AttrArchiveStatus' => 'Stato Archivio', - 'AttrAvgScore' => 'Punteggio medio', + 'AttrAvgScore' => 'Punteggio Medio', 'AttrCause' => 'Causa', 'AttrDiskBlocks' => 'Blocchi disco', 'AttrDiskPercent' => 'Percentuale disco', @@ -123,7 +123,7 @@ $SLANG = array( 'AttrFilterServer' => 'Filtro attivo su Server', // Added - 2018-08-30 'AttrFrames' => 'Immagini', 'AttrId' => 'Id', - 'AttrMaxScore' => 'Punteggio massimo', + 'AttrMaxScore' => 'Punteggio Massimo', 'AttrMonitorId' => 'Id Monitor', 'AttrMonitorName' => 'Nome Monitor', 'AttrMonitorServer' => 'Monitor attivo su Server', // Added - 2018-08-30 @@ -133,11 +133,11 @@ $SLANG = array( 'AttrStartDateTime' => 'Inizio - Data/orario', // Added - 2018-08-30 'AttrStartTime' => 'Inizio - Orario', // Added - 2018-08-30 'AttrStartWeekday' => 'Inizio - Giorno della settimana', // Added - 2018-08-30 - 'AttrStateId' => 'Stato esecuzione', // Added - 2018-08-30 - 'AttrStorageArea' => 'Area Salvataggio', // Added - 2018-08-30 - 'AttrStorageServer' => 'Server Salvataggio remoto', // Added - 2018-08-30 - 'AttrSystemLoad' => 'Carico di sistema', - 'AttrTotalScore' => 'Punteggio totale', + 'AttrStateId' => 'Stato Esecuzione', // Added - 2018-08-30 + 'AttrStorageArea' => 'Area Archiviazione', // Added - 2018-08-30 + 'AttrStorageServer' => 'Server Archiviazione remota', // Added - 2018-08-30 + 'AttrSystemLoad' => 'Carico Sistema', + 'AttrTotalScore' => 'Punteggio Totale', 'Auto' => 'Auto', 'AutoStopTimeout' => 'Auto Stop Timeout', 'Available' => 'Disponibile', // Added - 2009-03-31 @@ -181,7 +181,7 @@ $SLANG = array( 'BlobPx' => 'Blob Px', 'BlobSizes' => 'Dimensioni Blob', 'Blobs' => 'Blobs', - 'Brightness' => 'Luminosità;', + 'Brightness' => 'Luminosità', 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffers', 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 @@ -213,7 +213,7 @@ $SLANG = array( 'CanReboot' => 'Può Riavviare', 'CanSetPresets' => 'Può impostare preset', 'CanSleep' => 'Può andare in sleep', - 'CanTilt' => 'Può Tilt', + 'CanTilt' => 'Può inclinare', 'CanWake' => 'Può essere riattivato', 'CanWhite' => 'Può bilanciare il bianco', 'CanWhiteAbs' => 'Può bilanciare il bianco assoluto', @@ -238,8 +238,8 @@ $SLANG = array( 'ChooseLogFormat' => 'Scegli un formato di registro', // Added - 2011-06-17 'ChooseLogSelection' => 'Scegli una selezione del registro', // Added - 2011-06-17 'ChoosePreset' => 'Scegli Preset', - 'Clear' => 'Clear', // Added - 2011-06-16 - 'CloneMonitor' => 'Clone', // Added - 2018-08-30 + 'Clear' => 'Pulisci', // Added - 2011-06-16 + 'CloneMonitor' => 'Clona', // Added - 2018-08-30 'Close' => 'Chiudi', 'Colour' => 'Colori', 'Command' => 'Comando', @@ -257,25 +257,25 @@ $SLANG = array( 'Contrast' => 'Contrasto', 'Control' => 'Controllo', 'ControlAddress' => 'Indirizzo di controllo', - 'ControlCap' => 'Capacita\' di controllo', - 'ControlCaps' => 'Capacita\' di controllo', + 'ControlCap' => 'Capacità di controllo', + 'ControlCaps' => 'Capacità di controllo', 'ControlDevice' => 'Dispositivo di controllo', 'ControlType' => 'Tipo Controllo', 'Controllable' => 'Controllabile', - 'Current' => 'Current', // Added - 2015-04-18 + 'Current' => 'Corrente', // Added - 2015-04-18 'Cycle' => 'Cicla', 'CycleWatch' => 'Vista Ciclica', - 'DateTime' => 'Date/Time', // Added - 2011-06-16 + 'DateTime' => 'Data/Orario', // Added - 2011-06-16 'Day' => 'Giorno', 'Debug' => 'Debug', - 'DefaultRate' => 'Default Rate', + 'DefaultRate' => 'Rateo predefinito', 'DefaultScale' => 'Scala di default', - 'DefaultView' => 'Visualizzazione di default', - 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 - 'Delay' => 'Delay', // Added - 2015-04-18 + 'DefaultView' => 'Visualizzazione predefinita', + 'Deinterlacing' => 'Deinterlacciamento', // Added - 2015-04-18 + 'Delay' => 'Ritardo', // Added - 2015-04-18 'Delete' => 'Elimina', - 'DeleteAndNext' => 'Elimina & Prossimo', - 'DeleteAndPrev' => 'Elimina & Precedente', + 'DeleteAndNext' => 'Elimina e Prossimo', + 'DeleteAndPrev' => 'Elimina e Precedente', 'DeleteSavedFilter' => 'Elimina il filtro salvato', 'Description' => 'Descrizione', 'DetectedCameras' => 'Telecamere Rilevate', // Added - 2009-03-31 @@ -298,7 +298,7 @@ $SLANG = array( 'DonateRemindDay' => 'Non ancora, ricordamelo ancora tra 1 giorno', 'DonateRemindHour' => 'Non ancora, ricordamelo ancora tra 1 ora', 'DonateRemindMonth' => 'Non ancora, ricordamelo ancora tra 1 mese', - 'DonateRemindNever' => 'No, io non voglio donare, non lo faro\' mai', + 'DonateRemindNever' => 'No, io non voglio donare, non lo farò mai', 'DonateRemindWeek' => 'Non ancora, ricordamelo ancora tra 1 settimana', 'DonateYes' => 'Si,mi piacerebbe donare qualcosa ora', 'Download' => 'Scarica', @@ -363,12 +363,12 @@ $SLANG = array( 'First' => 'Primo', 'FlippedHori' => 'ribaltato orizzontale', 'FlippedVert' => 'ribaltato verticale', - 'FnMocord' => 'Mocord', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnNodect' => 'Nodect', // Added 2013.08.16. - 'FnNone' => 'None', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. + 'FnMocord' => 'Mocord - Registrazione continua (con evidenziazione eventi)', // Added 2013.08.16. + 'FnModect' => 'Modect - MOtion DEteCTtion (registrazione su rilevamento movimento)', // Added 2013.08.16. + 'FnMonitor' => 'Monitor - Visualizza Live', // Added 2013.08.16. + 'FnNodect' => 'Nodect - No DEteCTtion (registrazione su evento esterno)', // Added 2013.08.16. + 'FnNone' => 'None - Nessuno (Monitor disabilitato)', // Added 2013.08.16. + 'FnRecord' => 'Record - Registrazione continua', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => 'Forza Allarme', 'Format' => 'Formato', @@ -379,7 +379,7 @@ $SLANG = array( 'Frames' => 'Immagini', 'Func' => 'Funz', 'Function' => 'Funzione', - 'Gain' => 'Gain', + 'Gain' => 'Guadagno', 'General' => 'Generale', 'GenerateDownload' => 'Genera download', // Added - 2018-08-30 'GenerateVideo' => 'Genera video', @@ -391,7 +391,7 @@ $SLANG = array( 'HasFocusSpeed' => 'Ha velocità di focus', 'HasGainSpeed' => 'Ha velocità di guadagno', 'HasHomePreset' => 'Ha posizioni di present', - 'HasIrisSpeed' => 'Ha velocotà di iris', + 'HasIrisSpeed' => 'Ha velocità di iris', 'HasPanSpeed' => 'Ha velocità di Pan', 'HasPresets' => 'Ha preset', 'HasTiltSpeed' => 'Ha velocità di Tilt', @@ -414,7 +414,7 @@ $SLANG = array( 'In' => 'In', 'Include' => 'Includi', 'Inverted' => 'Invertito', - 'Iris' => 'Iris', + 'Iris' => 'Iride', 'KeyString' => 'Stringa Chiave', 'Label' => 'Etichetta', 'Language' => 'Linguaggio', @@ -438,7 +438,7 @@ $SLANG = array( 'Logout' => 'Logout', 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Bassa', - 'LowBW' => 'Banda Bassa', + 'LowBW' => 'Banda Bassa', 'Main' => 'Principale', 'Man' => 'Man', 'Manual' => 'Manuale', @@ -452,9 +452,9 @@ $SLANG = array( 'MaxGainRange' => 'Massimo range del guadagno', 'MaxGainSpeed' => 'Massima velocità del guadagno', 'MaxGainStep' => 'Massimo step del guadagno', - 'MaxIrisRange' => 'Massima range dell\'Iris', - 'MaxIrisSpeed' => 'Massima velocità dell\'Iris', - 'MaxIrisStep' => 'Massimo step dell\'Iris', + 'MaxIrisRange' => 'Massima range dell\'Iride', + 'MaxIrisSpeed' => 'Massima velocità dell\'Iride', + 'MaxIrisStep' => 'Massimo step dell\'Iride', 'MaxPanRange' => 'Massimo range del pan', 'MaxPanSpeed' => 'Massima velocità del tilt', 'MaxPanStep' => 'Massimo step del pan', @@ -470,7 +470,7 @@ $SLANG = array( 'MaximumFPS' => 'Massimi FPS', 'Medium' => 'Media', 'MediumBW' => 'Larghezza Banda Media', - 'Message' => 'Message', // Added - 2011-06-16 + 'Message' => 'Messaggio', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'L\'area minima dell\'allarme deve essere minore di quella massima', 'MinAlarmAreaUnset' => 'Devi specificare il numero minimo di pixel per l\'allarme', 'MinBlobAreaLtMax' => 'L\'area di blob minima deve essere minore dell\'area di blob massima', @@ -487,10 +487,10 @@ $SLANG = array( 'MinGainRange' => 'Minimo range del Guadagno', 'MinGainSpeed' => 'Velocità minima del Guadagno', 'MinGainStep' => 'Step minimo del guadagno', - 'MinIrisRange' => 'Range minimo dell\'Iris', - 'MinIrisSpeed' => 'Velocità minima dell\'Iris', - 'MinIrisStep' => 'Step minimo dell\'Iris', - 'MinPanRange' => 'Range minimo del pan', + 'MinIrisRange' => 'Range minimo dell\'Iride', + 'MinIrisSpeed' => 'Velocità minima dell\'Iride', + 'MinIrisStep' => 'Step minimo dell\'Iride', + 'MinPanRange' => 'Range minimo del Pan', 'MinPanSpeed' => 'Velocità minima del Pan', 'MinPanStep' => 'Step minimo del Pan', 'MinPixelThresLtMax' => 'I pixel minimi della soglia devono essere minori dei pixel massimi della soglia', @@ -550,7 +550,7 @@ $SLANG = array( 'NoneAvailable' => 'Nessuno disponibile', 'Normal' => 'Normale', 'Notes' => 'Note', - 'NumPresets' => 'Num Presets', + 'NumPresets' => 'Num redefiniti', 'Off' => 'Off', 'On' => 'On', 'OnvifCredentialsIntro'=> 'Fornire nome utente e password per la telecamera selezionata.
Se non è stato creato alcun utente per la videocamera, l\'utente qui indicato verrà creato con la password specificata.

', // Added - 2015-04-18 @@ -589,7 +589,7 @@ $SLANG = array( 'Paths' => 'Percorsi', 'Pause' => 'Pause', 'Phone' => 'Telefono', - 'PhoneBW' => 'Banda Tel', + 'PhoneBW' => 'Banda Tel', 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', @@ -598,11 +598,11 @@ $SLANG = array( 'PleaseWait' => 'Attendere prego', 'Plugins' => 'Plugins', 'Point' => 'Punto', - 'PostEventImageBuffer' => 'Buffer di immagini Dopo Evento', - 'PreEventImageBuffer' => 'Buffer di immagini Pre Evento', + 'PostEventImageBuffer' => 'Buffer immagini Dopo Evento', + 'PreEventImageBuffer' => 'Buffer immagini Pre Evento', 'PreserveAspect' => 'Preserve Aspect Ratio', 'Preset' => 'Preset', - 'Presets' => 'Presets', + 'Presets' => 'Predefiniti', 'Prev' => 'Prec', 'Probe' => 'Prova la telecamera', // Added - 2009-03-31 'ProfileProbe' => 'Prova lo stream', // Added - 2015-04-18 @@ -632,8 +632,8 @@ $SLANG = array( 'ReplayGapless' => 'Eventi continui', 'ReplaySingle' => 'Evento singolo', 'ReportEventAudit' => 'Rapporto Eventi di controllo', // Added - 2018-08-30 - 'Reset' => 'Resetta', - 'ResetEventCounts' => 'Resetta Contatore Eventi', + 'Reset' => 'Reset', + 'ResetEventCounts' => 'Reset Contatore Eventi', 'Restart' => 'Riavvia', 'Restarting' => 'Sto riavviando', 'RestrictedCameraIds' => 'Camera Ids Riservati', @@ -698,30 +698,30 @@ $SLANG = array( 'StepMedium' => 'Passo medio', 'StepNone' => 'Nessun passo', 'StepSmall' => 'Passo piccolo', - 'Stills' => 'Foto', + 'Stills' => 'Immagini fisse', 'Stop' => 'Stop', 'Stopped' => 'Inattivo', - 'StorageArea' => 'Area di salvataggio', // Added - 2018-08-30 - 'StorageScheme' => 'Scheme', // Added - 2018-08-30 - 'Stream' => 'Flusso', - 'StreamReplayBuffer' => 'Stream Replay Image Buffer', + 'StorageArea' => 'Area Archiviazione', // Added - 2018-08-30 + 'StorageScheme' => 'Schema Archiviazione', // Added - 2018-08-30 + 'Stream' => 'Stream', + 'StreamReplayBuffer' => 'Buffer immagini riproduzione stream', 'Submit' => 'Accetta', 'System' => 'Sistema', 'SystemLog' => 'Log di sistema', // Added - 2011-06-16 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Anteprima', - 'Tilt' => 'Tilt', + 'Tilt' => 'Tilt - Inclinazione', 'Time' => 'Ora', - 'TimeDelta' => 'Tempo di Delta', - 'TimeStamp' => 'Time Stamp', + 'TimeDelta' => 'Differenza orario', + 'TimeStamp' => 'Sovraimpressione data/orario', 'Timeline' => 'Linea Temporale', 'TimelineTip1' => 'Passa il mouse sul grafico per visualizzare un\'immagine dell\'istantanea e i dettagli dell\'evento.', // Added 2013.08.15. 'TimelineTip2' => 'Fai clic sulle sezioni colorate del grafico o sull\'immagine per visualizzare l\'evento.', // Added 2013.08.15. 'TimelineTip3' => 'Fare clic sullo sfondo per ingrandire un periodo di tempo più piccolo basato sul clic.', // Added 2013.08.15. 'TimelineTip4' => 'Utilizzare i controlli seguenti per ridurre o spostarsi avanti e indietro nell\'intervallo di tempo.', // Added 2013.08.15. - 'Timestamp' => 'Timestamp', - 'TimestampLabelFormat' => 'Formato etichetta timestamp', + 'Timestamp' => 'Sovraimpressione data/orario', + 'TimestampLabelFormat' => 'Formato etichetta Sovraimpressione data/orario', 'TimestampLabelSize' => 'Dimensione carattere', // Added - 2018-08-30 'TimestampLabelX' => 'coordinata X etichetta', 'TimestampLabelY' => 'coordinata Y etichetta', @@ -729,9 +729,9 @@ $SLANG = array( 'Tools' => 'Strumenti', 'Total' => 'Totale', // Added - 2011-06-16 'TotalBrScore' => 'Punteggio Totale', - 'TrackDelay' => 'Track Delay', - 'TrackMotion' => 'Track Motion', - 'Triggers' => 'Triggers', + 'TrackDelay' => 'Ritardo traccia', + 'TrackMotion' => 'Segui movimento', + 'Triggers' => 'Inneschi/Interruttori', 'TurboPanSpeed' => 'Velocità Turbo Pan', 'TurboTiltSpeed' => 'Velocità Turbo Tilt', 'Type' => 'Tipo', @@ -742,17 +742,17 @@ $SLANG = array( 'Update' => 'Aggiorna', 'UpdateAvailable' => 'Un aggiornamento di ZoneMinder è disponibilie.', 'UpdateNotNecessary' => 'Nessun aggiornamento necessario.', - 'Updated' => 'Updated', // Added - 2011-06-16 - 'Upload' => 'Upload', // Added - 2011-08-23 + 'Updated' => 'Aggiornato', // Added - 2011-06-16 + 'Upload' => 'Carica', // Added - 2011-08-23 'UseFilter' => 'Usa Filtro', 'UseFilterExprsPost' => ' espressioni filtri', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usa ', // This is used at the beginning of the phrase 'use N filter expressions' - 'UsedPlugins' => 'Used Plugins', + 'UsedPlugins' => 'Plugins in uso', 'User' => 'Utente', 'Username' => 'Nome Utente', 'Users' => 'Utenti', 'V4L' => 'V4L', // Added - 2015-04-18 - 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Rilevamenti per immagine', // Added - 2015-04-18 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Valore', 'Version' => 'Versione', @@ -769,7 +769,7 @@ $SLANG = array( 'VideoGenParms' => 'Parametri Generazione Video', 'VideoGenSucceeded' => 'Successo: Video Generato!', 'VideoSize' => 'Dimensioni Video', - 'VideoWriter' => 'Scrittore video', // Added - 2018-08-30 + 'VideoWriter' => 'Scrittore Video', // Added - 2018-08-30 'View' => 'Vedi', 'ViewAll' => 'Vedi Tutto', 'ViewEvent' => 'Vedi Evento', @@ -789,7 +789,7 @@ $SLANG = array( 'X10ActivationString' => 'Stringa attivazione X10', 'X10InputAlarmString' => 'Stringa allarme input X10', 'X10OutputAlarmString' => 'Stringa allarme output X10', - 'Y' => 'Y', + 'Y' => 'S', 'Yes' => 'Si', 'YouNoPerms' => 'Non hai i permessi per accedere a questa risorsa.', 'Zone' => 'Zona', From 787b7f1874141ca675081db0fe6b945d88fe078a Mon Sep 17 00:00:00 2001 From: Andrea Vezzali Date: Tue, 14 Sep 2021 15:39:53 +0200 Subject: [PATCH 025/290] Update it_it.php --- web/lang/it_it.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/lang/it_it.php b/web/lang/it_it.php index f06b18cc4..4cdb24ee9 100644 --- a/web/lang/it_it.php +++ b/web/lang/it_it.php @@ -631,7 +631,7 @@ $SLANG = array( 'ReplayAll' => 'Tutti gli Eventi', 'ReplayGapless' => 'Eventi continui', 'ReplaySingle' => 'Evento singolo', - 'ReportEventAudit' => 'Rapporto Eventi di controllo', // Added - 2018-08-30 + 'ReportEventAudit' => 'Controllo Eventi', // Added - 2018-08-30 'Reset' => 'Reset', 'ResetEventCounts' => 'Reset Contatore Eventi', 'Restart' => 'Riavvia', @@ -671,14 +671,14 @@ $SLANG = array( 'Size' => 'grandezza', 'SkinDescription' => 'Cambia la skin predefinita per questo computer', // Added - 2011-01-30 'Sleep' => 'Sleep', - 'SortAsc' => 'Cresc', + 'SortAsc' => 'Crescente', 'SortBy' => 'Ordina per', - 'SortDesc' => 'Decr', + 'SortDesc' => 'Decrescente', 'Source' => 'Sorgente', 'SourceColours' => 'Colori della Sorgente', // Added - 2009-02-08 'SourcePath' => 'Percorso della Sorgente', // Added - 2009-02-08 'SourceType' => 'Tipo Sorgente', - 'Speed' => 'Velocita\'', + 'Speed' => 'Velocità', 'SpeedHigh' => 'Alta Velocità', 'SpeedLow' => 'Bassa Velocità', 'SpeedMedium' => 'Media Velocità', @@ -708,10 +708,10 @@ $SLANG = array( 'Submit' => 'Accetta', 'System' => 'Sistema', 'SystemLog' => 'Log di sistema', // Added - 2011-06-16 - 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 + 'TargetColorspace' => 'Spazio dei colori obiettivo', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Anteprima', - 'Tilt' => 'Tilt - Inclinazione', + 'Tilt' => 'Tilt (Inclinazione)', 'Time' => 'Ora', 'TimeDelta' => 'Differenza orario', 'TimeStamp' => 'Sovraimpressione data/orario', From c7aa41502aea2b6ab65fcaec5fb8c5ffa2981897 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Sep 2021 10:26:07 -0400 Subject: [PATCH 026/290] Fix js error in montage review when using scaled mode. Fixes #3351 --- web/skins/classic/views/js/montagereview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index 4650e7e21..787a910d0 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -498,8 +498,8 @@ function redrawScreen() { drawGraph(); } + var monitors = $j('#monitors'); if ( fitMode == 1 ) { - var monitors = $j('#monitors'); var fps = $j('#fps'); var vh = window.innerHeight; var mh = (vh - monitors.position().top - fps.outerHeight()); From 120d9764bce6796e6e0e5bd979ae2104603a63df Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Sep 2021 13:38:55 -0400 Subject: [PATCH 027/290] notify anyone waiting in packetqueue before waiting on a packet in motion detection. Should fix decode lockup --- src/zm_monitor.cpp | 1 + src/zm_packetqueue.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 44e032979..5a2c646ab 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1846,6 +1846,7 @@ bool Monitor::Analyse() { while (!snap->decoded and !zm_terminate and !analysis_thread->Stopped()) { // Need to wait for the decoder thread. Debug(1, "Waiting for decode"); + packetqueue.notify_all(); // decode might be waiting packet_lock->wait(); if (!snap->image and snap->decoded) { Debug(1, "No image but was decoded, giving up"); diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index 7e2f367fc..2fc29ea33 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -81,6 +81,7 @@ class PacketQueue { ); bool is_there_an_iterator_pointing_to_packet(const std::shared_ptr &zm_packet); void unlock(ZMLockedPacket *lp); + void notify_all() { condition.notify_all(); }; }; #endif /* ZM_PACKETQUEUE_H */ From 8272411bb2320233035fff04be01a3e9b0e96e48 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Sep 2021 15:47:35 -0400 Subject: [PATCH 028/290] Revert "use get_packet_and_increment_it instead of the two step to improve locking" This reverts commit a44bbf8e345d3eefea92e2b05bb1034ae1bd46b7. --- src/zm_monitor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 5a2c646ab..eb65ac6f0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1723,7 +1723,7 @@ bool Monitor::Analyse() { // if have event, send frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. // get_analysis_packet will lock the packet and may wait if analysis_it is at the end - ZMLockedPacket *packet_lock = packetqueue.get_packet_and_increment_it(analysis_it); + ZMLockedPacket *packet_lock = packetqueue.get_packet(analysis_it); if (!packet_lock) return false; std::shared_ptr snap = packet_lock->packet_; @@ -1731,11 +1731,13 @@ bool Monitor::Analyse() { if (snap->score != -1) { Error("skipping because score was %d", snap->score); packetqueue.unlock(packet_lock); + packetqueue.increment_it(analysis_it); return false; } // Store the it that points to our snap we will need it later - packetqueue_iterator snap_it = std::prev(*analysis_it); + packetqueue_iterator snap_it = *analysis_it; + packetqueue.increment_it(analysis_it); // signal is set by capture bool signal = shared_data->signal; From de299ab8829d28e8fbe0e1cca1419f439c1590ac Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Sep 2021 16:21:32 -0400 Subject: [PATCH 029/290] More properly fix the threading lock. Instead of waiting on a packet, release it and wait on the packetqueue. --- src/zm_monitor.cpp | 30 +++++++++++++++++------------- src/zm_packetqueue.cpp | 9 +++++++++ src/zm_packetqueue.h | 3 ++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index eb65ac6f0..38160e354 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1735,10 +1735,6 @@ bool Monitor::Analyse() { return false; } - // Store the it that points to our snap we will need it later - packetqueue_iterator snap_it = *analysis_it; - packetqueue.increment_it(analysis_it); - // signal is set by capture bool signal = shared_data->signal; bool signal_change = (signal != last_signal); @@ -1848,8 +1844,15 @@ bool Monitor::Analyse() { while (!snap->decoded and !zm_terminate and !analysis_thread->Stopped()) { // Need to wait for the decoder thread. Debug(1, "Waiting for decode"); + packetqueue.unlock(packet_lock); packetqueue.notify_all(); // decode might be waiting - packet_lock->wait(); + packetqueue.wait(); + + // Another thread may have moved our it. Unlikely but possible + packet_lock = packetqueue.get_packet(analysis_it); + if (!packet_lock) return false; + snap = packet_lock->packet_; + if (!snap->image and snap->decoded) { Debug(1, "No image but was decoded, giving up"); delete packet_lock; @@ -1947,14 +1950,14 @@ bool Monitor::Analyse() { // Must start on a keyframe so rewind. Only for passthrough though I guess. // FIXME this iterator is not protected from invalidation packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it( - snap_it, 0 /* pre_event_count */ + *analysis_it, 0 /* pre_event_count */ ); // This gets a lock on the starting packet ZMLockedPacket *starting_packet_lock = nullptr; std::shared_ptr starting_packet = nullptr; - if (*start_it != snap_it) { + if (*start_it != *analysis_it) { starting_packet_lock = packetqueue.get_packet(start_it); if (!starting_packet_lock) { Warning("Unable to get starting packet lock"); @@ -1968,12 +1971,12 @@ bool Monitor::Analyse() { event = new Event(this, starting_packet->timestamp, "Continuous", noteSetMap); // Write out starting packets, do not modify packetqueue it will garbage collect itself - while (starting_packet and ((*start_it) != snap_it)) { + while (starting_packet and ((*start_it) != *analysis_it)) { event->AddPacket(starting_packet); // Have added the packet, don't want to unlock it until we have locked the next packetqueue.increment_it(start_it); - if ((*start_it) == snap_it) { + if ((*start_it) == *analysis_it) { if (starting_packet_lock) delete starting_packet_lock; break; } @@ -2051,12 +2054,12 @@ bool Monitor::Analyse() { if (!event) { packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it( - snap_it, + *analysis_it, (pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count) ); ZMLockedPacket *starting_packet_lock = nullptr; std::shared_ptr starting_packet = nullptr; - if (*start_it != snap_it) { + if (*start_it != *analysis_it) { starting_packet_lock = packetqueue.get_packet(start_it); if (!starting_packet_lock) return false; starting_packet = starting_packet_lock->packet_; @@ -2071,11 +2074,11 @@ bool Monitor::Analyse() { shared_data->state = state = ALARM; // Write out starting packets, do not modify packetqueue it will garbage collect itself - while (*start_it != snap_it) { + while (*start_it != *analysis_it) { event->AddPacket(starting_packet); packetqueue.increment_it(start_it); - if ( (*start_it) == snap_it ) { + if ( (*start_it) == (*analysis_it) ) { if (starting_packet_lock) delete starting_packet_lock; break; } @@ -2262,6 +2265,7 @@ bool Monitor::Analyse() { if (function == MODECT or function == MOCORD) UpdateAnalysisFPS(); } + packetqueue.increment_it(analysis_it); packetqueue.unlock(packet_lock); shared_data->last_read_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 67ba35c0f..43ab20d1e 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -663,3 +663,12 @@ void PacketQueue::setPreEventVideoPackets(int p) { pre_event_video_packet_count = 1; // We can simplify a lot of logic in queuePacket if we can assume at least 1 packet in queue } + +void PacketQueue::notify_all() { + condition.notify_all(); +}; + +void PacketQueue::wait() { + std::unique_lock lck(mutex); + condition.wait(lck); +} diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index 2fc29ea33..20cfdfe85 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -81,7 +81,8 @@ class PacketQueue { ); bool is_there_an_iterator_pointing_to_packet(const std::shared_ptr &zm_packet); void unlock(ZMLockedPacket *lp); - void notify_all() { condition.notify_all(); }; + void notify_all(); + void wait(); }; #endif /* ZM_PACKETQUEUE_H */ From cddb9d88bf4eb59e70fb2e87ce18e093521f0457 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Sep 2021 18:08:50 -0400 Subject: [PATCH 030/290] Add support for package version --- utils/packpack/startpackpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index e8a8a182d..2ea949078 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -223,7 +223,7 @@ setdebpkgname () { if [ "" == "$VERSION" ]; then export VERSION="${versionfile}~${thedate}.${numcommits}" fi - export RELEASE="${DIST}" + export RELEASE="${DIST}${PACKAGE_VERSION}" checkvars From 38cda24b5383b79b92ed659455ee9f33a5c6ce9b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 15 Sep 2021 12:53:41 -0400 Subject: [PATCH 031/290] wait won't wake up other threads, so notify first. Since we have the lock, this should be ok --- src/zm_packetqueue.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 43ab20d1e..cef7e8e2f 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -133,6 +133,7 @@ bool PacketQueue::queuePacket(std::shared_ptr add_packet) { if (max_video_packet_count > 0) { while (packet_counts[video_stream_id] > max_video_packet_count) { Error("Unable to free up older packets. Waiting."); + condition.notify_all(); condition.wait(lck); if (deleting or zm_terminate) return false; From c5f46231042195d25dad3c321bcb1a5579d77c39 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 15 Sep 2021 12:55:49 -0400 Subject: [PATCH 032/290] Don't crash when unable to create source. erase will call the desctructor. Fixes #3344 --- src/zm_rtsp_server.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zm_rtsp_server.cpp b/src/zm_rtsp_server.cpp index 2276850cd..ea6f4e2b7 100644 --- a/src/zm_rtsp_server.cpp +++ b/src/zm_rtsp_server.cpp @@ -269,9 +269,8 @@ int main(int argc, char *argv[]) { Warning("Unknown format in %s", videoFifoPath.c_str()); } if (videoSource == nullptr) { - Error("Unable to create source"); + Error("Unable to create source for %s", videoFifoPath.c_str()); rtspServer->RemoveSession(sessions[monitor->Id()]->GetMediaSessionId()); - delete sessions[monitor->Id()]; sessions.erase(monitor->Id()); continue; } From e63be2b18ed3b362b5db198d7da16204f00a6cd7 Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Wed, 15 Sep 2021 10:13:02 -0700 Subject: [PATCH 033/290] Fixed a bug in Image::Buffer that would return the wrong location in the image if the image had > 1 channels (and if the request were for x > 0). --- src/zm_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_image.h b/src/zm_image.h index ccbae9f86..24626d789 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -181,7 +181,7 @@ class Image { /* Internal buffer should not be modified from functions outside of this class */ inline const uint8_t* Buffer() const { return buffer; } - inline const uint8_t* Buffer(unsigned int x, unsigned int y=0) const { return &buffer[(y*linesize)+x]; } + inline const uint8_t* Buffer(unsigned int x, unsigned int y=0) const { return &buffer[(y*linesize) + x*colours]; } /* Request writeable buffer */ uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder); // Is only acceptable on a pre-allocated buffer From c233ec3b8c63f7c602395ccdb88bed0cc362b247 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 15 Sep 2021 13:38:00 -0400 Subject: [PATCH 034/290] Remove redundant notify_all, spelling mistake --- src/zm_monitor.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 38160e354..9a5144623 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1844,8 +1844,7 @@ bool Monitor::Analyse() { while (!snap->decoded and !zm_terminate and !analysis_thread->Stopped()) { // Need to wait for the decoder thread. Debug(1, "Waiting for decode"); - packetqueue.unlock(packet_lock); - packetqueue.notify_all(); // decode might be waiting + packetqueue.unlock(packet_lock); // This will delete packet_lock and notify_all packetqueue.wait(); // Another thread may have moved our it. Unlikely but possible @@ -3070,7 +3069,7 @@ int Monitor::PrimeCapture() { Debug(1, "Creating decoder thread"); decoder = zm::make_unique(this); } else { - Debug(1, "Restartg decoder thread"); + Debug(1, "Restarting decoder thread"); decoder->Start(); } } From 874552c06b2de7b5fd329d09a88bbd96febc3475 Mon Sep 17 00:00:00 2001 From: ColorfullyZhang <36832299+ColorfullyZhang@users.noreply.github.com> Date: Thu, 16 Sep 2021 14:41:24 +0800 Subject: [PATCH 035/290] Set mysql character set to utf8 explicitly to support chinese characters (or other special characters). --- src/zm_db.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 0d499edbd..c6cc452b9 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -102,6 +102,7 @@ bool zmDbConnect() { if ( mysql_query(&dbconn, "SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED") ) { Error("Can't set isolation level: %s", mysql_error(&dbconn)); } + mysql_set_character_set(&dbconn, "utf8"); zmDbConnected = true; return zmDbConnected; } From 9e4f203632bad8193f07bd9cc64834a00a9b684d Mon Sep 17 00:00:00 2001 From: ColorfullyZhang <36832299+ColorfullyZhang@users.noreply.github.com> Date: Thu, 16 Sep 2021 18:24:37 +0800 Subject: [PATCH 036/290] Set character set as utf8 when connect to mysql to avoid mistakes when there are Chinese characters in storage path. --- scripts/ZoneMinder/lib/ZoneMinder/Database.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index 18df301f3..35d2dc6fa 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -107,6 +107,7 @@ sub zmDbConnect { .$socket . $sslOptions . ($options?join(';', '', map { $_.'='.$$options{$_} } keys %{$options} ) : '') , $ZoneMinder::Config::Config{ZM_DB_USER} , $ZoneMinder::Config::Config{ZM_DB_PASS} + , { mysql_enable_utf8 => 1, } ); }; if ( !$dbh or $@ ) { From 0bf417bae0736673ce987d2924a8f610b89b0eaf Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 16 Sep 2021 10:03:21 -0400 Subject: [PATCH 037/290] Reduce logging level to debug dealing with index == -1, which is used in zmu to mean the last captured image. Fixes #3354 --- src/zm_monitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 9a5144623..723d4f7b5 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1153,7 +1153,7 @@ void Monitor::AddPrivacyBitmask() { int Monitor::GetImage(int32_t index, int scale) { if (index < 0 || index > image_buffer_count) { - Warning("Invalid index %d passed. image_buffer_count = %d", index, image_buffer_count); + Debug(1, "Invalid index %d passed. image_buffer_count = %d", index, image_buffer_count); index = shared_data->last_write_index; } if (!image_buffer.size() or static_cast(index) >= image_buffer.size()) { From e75d5a89e928c9f47a6e3ac17027498e5e0eedc8 Mon Sep 17 00:00:00 2001 From: Andrea Vezzali Date: Mon, 20 Sep 2021 14:02:35 +0200 Subject: [PATCH 038/290] Update italian (it_it) translation (#3357) --- web/lang/it_it.php | 105 +++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/web/lang/it_it.php b/web/lang/it_it.php index 4cdb24ee9..55fb3b34a 100644 --- a/web/lang/it_it.php +++ b/web/lang/it_it.php @@ -184,46 +184,46 @@ $SLANG = array( 'Brightness' => 'Luminosità', 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffers', - 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 - 'CanAutoFocus' => 'Può Auto Focus', - 'CanAutoGain' => 'Può Auto Gains', - 'CanAutoIris' => 'Può Auto Iris', - 'CanAutoWhite' => 'Può Auto bil bianco', - 'CanAutoZoom' => 'Può Auto Zoom', - 'CanFocus' => 'Può Fuoco', - 'CanFocusAbs' => 'Può Fuoco Assoluto', - 'CanFocusCon' => 'Può Fuoco Continuo ', - 'CanFocusRel' => 'Può Fuoco Relativo', - 'CanGain' => 'Può Gain ', - 'CanGainAbs' => 'Può Gain Assoluto', - 'CanGainCon' => 'Può Gain Continuo ', - 'CanGainRel' => 'Può Gain Relativo', - 'CanIris' => 'Può Iris', - 'CanIrisAbs' => 'Può Iris Assoluto', - 'CanIrisCon' => 'Può Iris Continuo ', - 'CanIrisRel' => 'Può Iris Relativo', - 'CanMove' => 'Può Mov.', - 'CanMoveAbs' => 'Può Mov. Assoluto', - 'CanMoveCon' => 'Può Mov. Continuo ', - 'CanMoveDiag' => 'Può Mov. Diagonale ', - 'CanMoveMap' => 'Può Mov Mappato', - 'CanMoveRel' => 'Può Mov. Relativo', - 'CanPan' => 'Può Pan' , - 'CanReset' => 'Può Reset', - 'CanReboot' => 'Può Riavviare', - 'CanSetPresets' => 'Può impostare preset', - 'CanSleep' => 'Può andare in sleep', + 'CSSDescription' => 'Modificare il css predefinito per questo computer', // Added - 2015-04-18 + 'CanAutoFocus' => 'Può impostare Auto Focus', + 'CanAutoGain' => 'Può impostare Auto Gains', + 'CanAutoIris' => 'Può impostare Auto Iris', + 'CanAutoWhite' => 'Può impostare Auto bil bianco', + 'CanAutoZoom' => 'Può impostare Auto Zoom', + 'CanFocus' => 'Può impostare Fuoco', + 'CanFocusAbs' => 'Può impostare Fuoco Assoluto', + 'CanFocusCon' => 'Può impostare Fuoco Continuo', + 'CanFocusRel' => 'Può impostare Fuoco Relativo', + 'CanGain' => 'Può impostare Guadagno', + 'CanGainAbs' => 'Può impostare Guadagno Assoluto', + 'CanGainCon' => 'Può impostare Guadagno Continuo ', + 'CanGainRel' => 'Può impostare Guadagno Relativo', + 'CanIris' => 'Può impostare Iride', + 'CanIrisAbs' => 'Può impostare Iride Assoluto', + 'CanIrisCon' => 'Può impostare Iride Continuo', + 'CanIrisRel' => 'Può impostare Iride Relativo', + 'CanMove' => 'Può impostare Movimento', + 'CanMoveAbs' => 'Può impostare Movimento Assoluto', + 'CanMoveCon' => 'Può impostare Movimento Continuo', + 'CanMoveDiag' => 'Può impostare Movimento Diagonale', + 'CanMoveMap' => 'Può impostare Movimento Mappato', + 'CanMoveRel' => 'Può impostare Movimento Relativo', + 'CanPan' => 'Può impostare Panoramica' , + 'CanReset' => 'Può effettuare Reset', + 'CanReboot' => 'Può Riavviare', + 'CanSetPresets' => 'Può impostare Preset', + 'CanSleep' => 'Può sospendere', 'CanTilt' => 'Può inclinare', - 'CanWake' => 'Può essere riattivato', + 'CanWake' => 'Può riattivare', 'CanWhite' => 'Può bilanciare il bianco', 'CanWhiteAbs' => 'Può bilanciare il bianco assoluto', 'CanWhiteBal' => 'Può bilanciare il bianco', 'CanWhiteCon' => 'Può bilanciare il bianco Continuo', 'CanWhiteRel' => 'Può bilanciare il bianco Relativo', - 'CanZoom' => 'Può Zoom', - 'CanZoomAbs' => 'Può Zoom Assoluto', - 'CanZoomCon' => 'Può Zoom Continuo', - 'CanZoomRel' => 'Può Zoom Relativo', + 'CanZoom' => 'Può impostare Zoom', + 'CanZoomAbs' => 'Può impostare Zoom Assoluto', + 'CanZoomCon' => 'Può impostare Zoom Continuo', + 'CanZoomRel' => 'Può impostare Zoom Relativo', 'Cancel' => 'Annulla', 'CancelForcedAlarm' => 'Annulla Allarme Forzato', 'CaptureHeight' => 'Altezza Cattura Immagine', @@ -401,6 +401,7 @@ $SLANG = array( 'HasZoomSpeed' => 'Ha velocità di zoom', 'High' => 'Alta', 'HighBW' => 'Banda Alta', + 'Hight' => 'Altezza', 'Home' => 'Home', 'Hostname' => 'Nome Host', // Added - 2018-08-30 'Hour' => 'Ora', @@ -508,10 +509,10 @@ $SLANG = array( 'Mode' => 'Modalità', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Monitor Ids', - 'MonitorPreset' => 'Monitor Presenti', - 'MonitorPresetIntro' => 'Selezionare un appropriato pre settaggio dalla lista riportata qui sotto.

Per favore notare che questo potrebbe sovrascrivere ogni valore che hai già configurato su questo monitor.

', + 'MonitorPreset' => 'Monitor Preset', + 'MonitorPresetIntro' => 'Selezionare un preset appropriato dalla lista riportata qui sotto.

Notare che questo potrebbe sovrascrivere ogni valore che hai già configurato su questo monitor.

', 'MonitorProbe' => 'Prova Monitor', // Added - 2009-03-31 - 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2009-03-31 + 'MonitorProbeIntro' => 'L\'elenco seguente mostra le telecamere analogiche e di rete rilevate e se sono già in uso o disponibili per la selezione.

Selezionare la voce desiderata dall\'elenco seguente.

Si noti che non tutte le telecamere possono essere rilevate e che la scelta di una telecamera qui potrebbe sovrascrivere tutti i valori già configurati per il monitor corrente.

', // Added - 2009-03-31 'Monitors' => 'Monitors', 'Montage' => 'Montaggio', 'MontageReview' => 'Revisione del montaggio', // Added - 2018-08-30 @@ -661,16 +662,17 @@ $SLANG = array( 'SelectMonitors' => 'Monitor Selezionati', 'SelfIntersecting' => 'I vertici del poligono non devono intersecarsi', 'Set' => 'Imposta', - 'SetNewBandwidth' => 'Imposta nuova Banda', - 'SetPreset' => 'Imposta Preset', + 'SetNewBandwidth' => 'Imposta Nuova Banda', + 'SetPreset' => 'Imposta Predefiniti', 'Settings' => 'Impostazioni', - 'ShowFilterWindow' => 'MostraFinestraFiltri', + 'ShowFilterWindow' => 'Mostra Finestra Filtri', 'ShowTimeline' => 'Mostra linea temporale', + 'Show Zones' => 'Visualizza Zone', 'SignalCheckColour' => 'Colore controllo segnale', 'SignalCheckPoints' => 'Punti di controllo segnale', // Added - 2018-08-30 'Size' => 'grandezza', 'SkinDescription' => 'Cambia la skin predefinita per questo computer', // Added - 2011-01-30 - 'Sleep' => 'Sleep', + 'Sleep' => 'Sospendi', 'SortAsc' => 'Crescente', 'SortBy' => 'Ordina per', 'SortDesc' => 'Decrescente', @@ -747,7 +749,7 @@ $SLANG = array( 'UseFilter' => 'Usa Filtro', 'UseFilterExprsPost' => ' espressioni filtri', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usa ', // This is used at the beginning of the phrase 'use N filter expressions' - 'UsedPlugins' => 'Plugins in uso', + 'UsedPlugins' => 'Plugins in uso', 'User' => 'Utente', 'Username' => 'Nome Utente', 'Users' => 'Utenti', @@ -784,6 +786,7 @@ $SLANG = array( 'White' => 'Bianco', 'WhiteBalance' => 'Bilanciamento del Bianco', 'Wide' => 'Larghezza', + 'Width' => 'Larghezza', 'X' => 'X', 'X10' => 'X10', 'X10ActivationString' => 'Stringa attivazione X10', @@ -937,17 +940,17 @@ function zmVlang( $langVarArray, $count ) // So for example, to override the help text for ZM_LANG_DEFAULT do $OLANG = array( 'OPTIONS_FFMPEG' => array( - 'Help' => "Parameters in this field are passed on to FFmpeg. Multiple parameters can be separated by ,~~ ". - "Examples (do not enter quotes)~~~~". - "\"allowed_media_types=video\" Set datatype to request fromcam (audio, video, data)~~~~". - "\"reorder_queue_size=nnn\" Set number of packets to buffer for handling of reordered packets~~~~". - "\"loglevel=debug\" Set verbosity of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)" + 'Help' => "I parametri in questo campo vengono passati a FFmpeg. Più parametri possono essere separati da ,~~ ". + "Esempi (non inserire virgolette)~~~~". + "\"allowed_media_types=video\" Imposta il tipo di dati da richiedere dalla telecamera (audio, video, data)~~~~". + "\"reorder_queue_size=nnn\" Imposta il numero di pacchetti nel buffer per la gestione dei pacchetti riordinati~~~~". + "\"loglevel=debug\" Imposta la verbosità di FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)" ), 'OPTIONS_LIBVLC' => array( - 'Help' => "Parameters in this field are passed on to libVLC. Multiple parameters can be separated by ,~~ ". - "Examples (do not enter quotes)~~~~". - "\"--rtp-client-port=nnn\" Set local port to use for rtp data~~~~". - "\"--verbose=2\" Set verbosity of libVLC" + 'Help' => "I parametri in questo campo vengono passati a libVLC. Più parametri possono essere separati da ,~~ ". + "Esempi (non inserire virgolette)~~~~". + "\"--rtp-client-port=nnn\" Imposta la porta locale da utilizzare per i dati RTP~~~~". + "\"--verbose=2\" Imposta la verbosità di of libVLC" ), From d81be9701a64a61a603dc0be58ca60d080ad9584 Mon Sep 17 00:00:00 2001 From: 5472qaywsx <39193575+5472qaywsx@users.noreply.github.com> Date: Mon, 20 Sep 2021 14:04:07 +0200 Subject: [PATCH 039/290] Docs: Fix a typo (#3358) --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index fc1d6c077..64a6b4004 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -77,7 +77,7 @@ To start the build, simply execute the following command from the root folder of OS= DIST= utils/packpack/startpackpack.sh -Where is the name of the distro you wish to build on, such as fedora, and is release name or number of the distro you wish to build on. Redhat distros expect a number for while Debian and Ubuntu distros expect a name. For example: +Where is the name of the distro you wish to build on, such as fedora, and is the release name or number of the distro you wish to build on. Redhat distros expect a number for while Debian and Ubuntu distros expect a name. For example: :: From 2a0ddc6337c4b46ac859a0ffa6179e20d5b34dfc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 20 Sep 2021 13:48:13 -0400 Subject: [PATCH 040/290] Add open collective username --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 8804e639c..5994f0e6b 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,7 +2,7 @@ github: [connortechnology,pliablepixels] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: zoneminder # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username +open_collective: zoneminder # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry From 4bdf965dcb453273069dd0f4ce7a8233064f41f2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 20 Sep 2021 16:02:37 -0400 Subject: [PATCH 041/290] Set rows on email textarea --- web/skins/classic/views/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index efb3eed15..60cc585d4 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -493,7 +493,7 @@ if ( ZM_OPT_EMAIL ) {

- +

Date: Tue, 21 Sep 2021 12:59:42 -0400 Subject: [PATCH 042/290] Always include the download button so that we can assume that it exists in the js. So avoid console errors when no mp4. --- web/skins/classic/views/event.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 81ff15075..a07c95042 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -149,13 +149,10 @@ if ( $Event->Id() and !file_exists($Event->Path()) ) -DefaultVideo() ) { -?> - - + DefaultVideo() ? '' : 'style="display:none;"' ?> +> From 92f6d3cbae0e41ffe4f093b593ce117b14720cab Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 21 Sep 2021 13:00:47 -0400 Subject: [PATCH 043/290] Restore the download button's behaviour. It is a simple link to the mp4, not an export. Also add a handler for the video.js rate control to sync up our non video.js rate dropdown and stored cookie. --- web/skins/classic/views/js/event.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index e2d3c9ce3..727976e76 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -891,6 +891,12 @@ function initPage() { vid.on('timeupdate', function() { $j('#progressValue').html(secsToTime(Math.floor(vid.currentTime()))); }); + vid.on('ratechange', function() { + rate = vid.playbackRate() * 100; + console.log("rate change " + rate); + $j('select[name="rate"]').val(rate); + setCookie('zmEventRate', rate, 3600); + }); // rate is in % so 100 would be 1x if (rate > 0) { @@ -1012,19 +1018,6 @@ function initPage() { window.location.assign('?view=export&eids[]='+eventData.Id); }); - // Manage the DOWNLOAD VIDEO button - bindButton('#downloadBtn', 'click', null, function onDownloadClick(evt) { - evt.preventDefault(); - $j.getJSON(thisUrl + '?request=modal&modal=download&eids[]='+eventData.Id) - .done(function(data) { - insertModalHtml('downloadModal', data.html); - $j('#downloadModal').modal('show'); - // Manage the GENERATE DOWNLOAD button - $j('#exportButton').click(exportEvent); - }) - .fail(logAjaxFail); - }); - // Manage the Event STATISTICS Button bindButton('#statsBtn', 'click', null, function onStatsClick(evt) { evt.preventDefault(); From 568be3fc549f2e8d258077982494c82c560bc135 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 21 Sep 2021 14:29:05 -0400 Subject: [PATCH 044/290] initialize video_first_pts and when setting it need to specify microseconds otherwise we get nanoseconds. White space. --- src/zm_ffmpeg_camera.cpp | 4 ++-- src/zm_packet.cpp | 2 +- src/zm_packet.h | 3 ++- src/zm_videostore.cpp | 8 +++++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 1484d5234..82471c3dc 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -231,8 +231,8 @@ int FfmpegCamera::Capture(std::shared_ptr &zm_packet) { zm_packet->set_packet(&packet); zm_packet->stream = stream; zm_packet->pts = av_rescale_q(packet.pts, stream->time_base, AV_TIME_BASE_Q); - if ( packet.pts != AV_NOPTS_VALUE ) { - if ( stream == mVideoStream ) { + if (packet.pts != AV_NOPTS_VALUE) { + if (stream == mVideoStream) { if (mFirstVideoPTS == AV_NOPTS_VALUE) mFirstVideoPTS = packet.pts; diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 3361667e0..55a78721e 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -83,7 +83,7 @@ ZMPacket::ZMPacket(ZMPacket &p) : av_init_packet(&packet); packet.size = 0; packet.data = nullptr; - if ( zm_av_packet_ref(&packet, &p.packet) < 0 ) { + if (zm_av_packet_ref(&packet, &p.packet) < 0) { Error("error refing packet"); } } diff --git a/src/zm_packet.h b/src/zm_packet.h index 66a6250ca..9cce4dd03 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -66,7 +66,7 @@ class ZMPacket { Image *set_image(Image *); int is_keyframe() { return keyframe; }; - int decode( AVCodecContext *ctx ); + int decode(AVCodecContext *ctx); explicit ZMPacket(Image *image, SystemTimePoint tv); explicit ZMPacket(ZMPacket &packet); ZMPacket(); @@ -88,6 +88,7 @@ class ZMLockedPacket { lck_(packet_->mutex_, std::defer_lock), locked(false) { } + ~ZMLockedPacket() { if (locked) unlock(); } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 67f31cabc..1bd0724d5 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -93,6 +93,7 @@ VideoStore::VideoStore( converted_in_samples(nullptr), filename(filename_in), format(format_in), + video_first_pts(0), video_first_dts(0), audio_first_pts(0), audio_first_dts(0), @@ -990,23 +991,24 @@ int VideoStore::writeVideoFramePacket(const std::shared_ptr &zm_packet frame->pkt_duration = 0; if (!video_first_pts) { - video_first_pts = zm_packet->timestamp.time_since_epoch().count(); + video_first_pts = static_cast(std::chrono::duration_cast(zm_packet->timestamp.time_since_epoch()).count()); Debug(2, "No video_first_pts, set to (%" PRId64 ") secs(%.2f)", video_first_pts, FPSeconds(zm_packet->timestamp.time_since_epoch()).count()); frame->pts = 0; } else { + Microseconds useconds = std::chrono::duration_cast( zm_packet->timestamp - SystemTimePoint(Microseconds(video_first_pts))); frame->pts = av_rescale_q(useconds.count(), AV_TIME_BASE_Q, video_out_ctx->time_base); Debug(2, - "Setting pts for frame(%d) to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - us(%" PRIi64 ") @ %d/%d", + "Setting pts for frame(%d) to (%" PRId64 ") from (zm_packet->timestamp(%" PRIi64 " - first %" PRId64 " us %" PRId64 " ) @ %d/%d", frame_count, frame->pts, + static_cast(std::chrono::duration_cast(zm_packet->timestamp.time_since_epoch()).count()), video_first_pts, static_cast(std::chrono::duration_cast(useconds).count()), - static_cast(std::chrono::duration_cast(zm_packet->timestamp.time_since_epoch()).count()), video_out_ctx->time_base.num, video_out_ctx->time_base.den); } From e98728c529a2f541b8fc59914c1b75ed7c8b1681 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 23 Sep 2021 16:04:36 -0400 Subject: [PATCH 045/290] Set new defaults for various settings --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 0c8aec4a2..31d92bf11 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -308,7 +308,7 @@ our @options = ( }, { name => 'ZM_AUTH_HASH_IPS', - default => 'yes', + default => 'no', description => 'Include IP addresses in the authentication hash', help => q` When ZoneMinder is running in hashed authenticated mode it can @@ -346,7 +346,7 @@ our @options = ( }, { name => 'ZM_AUTH_HASH_LOGINS', - default => 'no', + default => 'yes', description => 'Allow login by authentication hash', help => q` The normal process for logging into ZoneMinder is via the login @@ -508,7 +508,7 @@ our @options = ( }, { name => 'ZM_SYSTEM_SHUTDOWN', - default => 'yes', + default => 'no', description => 'Allow Admin users to power off or restart the system from the ZoneMinder UI.', help => 'The system will need to have sudo installed and the following added to /etc/sudoers~~ ~~ @@ -1096,7 +1096,7 @@ our @options = ( }, { name => 'ZM_LOG_LEVEL_SYSLOG', - default => '0', + default => '-1', description => 'Save logging output to the system log', help => q` ZoneMinder logging is now more integrated between @@ -1604,7 +1604,7 @@ our @options = ( }, { name => 'ZM_WEB_EVENT_DISK_SPACE', - default => 'no', + default => 'yes', description => 'Whether to show disk space used by each event.', help => q` Adds another column to the listing of events @@ -1634,7 +1634,7 @@ our @options = ( }, { name => 'ZM_WEB_ID_ON_CONSOLE', - default => 'no', + default => 'yes', description => 'Should the console list the monitor id', help => q` Some find it useful to have the id always visible @@ -2270,7 +2270,7 @@ our @options = ( }, { name => 'ZM_MAX_RESTART_DELAY', - default => '600', + default => '30', description => 'Maximum delay (in seconds) for daemon restart attempts.', help => q` The zmdc (zm daemon control) process controls when processeses From b8022cdda266817191e01d768080455f02829ddb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 23 Sep 2021 16:06:18 -0400 Subject: [PATCH 046/290] More new defaults. The navbar refreshes every 60 secs so make full page refresh be 240sec. Ajax timeout needs to be 10 seconds. Large event listings can take longer than 3 --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 31d92bf11..ff802dd15 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -2855,7 +2855,7 @@ our @options = ( }, { name => 'ZM_WEB_H_REFRESH_MAIN', - default => '60', + default => '240', introduction => q` There are now a number of options that are grouped into bandwidth categories, this allows you to configure the @@ -3113,7 +3113,7 @@ our @options = ( }, { name => 'ZM_WEB_H_AJAX_TIMEOUT', - default => '3000', + default => '10000', description => 'How long to wait for Ajax request responses (ms)', help => q` The newer versions of the live feed and event views use Ajax to From 655daf4fbeaac2821e23c0ca8b28073a77d1ab30 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 23 Sep 2021 16:39:28 -0400 Subject: [PATCH 047/290] Add mmal device/pix fmt type --- src/zm_ffmpeg_camera.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 82471c3dc..6415b2134 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -55,31 +55,24 @@ static enum AVPixelFormat get_hw_format( } #if !LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0) static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) { - enum AVPixelFormat fmt; switch (type) { case AV_HWDEVICE_TYPE_VAAPI: - fmt = AV_PIX_FMT_VAAPI; - break; + return AV_PIX_FMT_VAAPI; case AV_HWDEVICE_TYPE_DXVA2: - fmt = AV_PIX_FMT_DXVA2_VLD; - break; + return AV_PIX_FMT_DXVA2_VLD; case AV_HWDEVICE_TYPE_D3D11VA: - fmt = AV_PIX_FMT_D3D11; - break; + return = AV_PIX_FMT_D3D11; case AV_HWDEVICE_TYPE_VDPAU: - fmt = AV_PIX_FMT_VDPAU; - break; + return AV_PIX_FMT_VDPAU; case AV_HWDEVICE_TYPE_CUDA: - fmt = AV_PIX_FMT_CUDA; - break; + return AV_PIX_FMT_CUDA; + case AV_HWDEVICE_TYPE_MMAL: + return AV_PIX_FMT_MMAL; case AV_HWDEVICE_TYPE_VIDEOTOOLBOX: - fmt = AV_PIX_FMT_VIDEOTOOLBOX; - break; + return AV_PIX_FMT_VIDEOTOOLBOX; default: - fmt = AV_PIX_FMT_NONE; - break; + return AV_PIX_FMT_NONE; } - return fmt; } #endif #endif From 2e4bb73204b977123a72aef4784dfa890c1ea8a3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 14:27:10 -0400 Subject: [PATCH 048/290] remove useless commit. --- scripts/zmfilter.pl.in | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 64a20b4d5..1e62cb229 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -399,7 +399,6 @@ sub checkFilter { ) { $Event->save(); } - $ZoneMinder::Database::dbh->commit() if !$$filter{LockRows}; } # end if UpdateDiskSpace } # end foreach event ZoneMinder::Database::end_transaction($dbh, $in_transaction) if $$filter{LockRows}; From cbc376bb5a9df2f3b1d6cf02d5452c73053d7c17 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 16:08:58 -0400 Subject: [PATCH 049/290] Add zm_rtsp_server to ignores --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e617d937c..3d61b4f54 100644 --- a/.gitignore +++ b/.gitignore @@ -124,6 +124,7 @@ src/zmc src/zmf src/zms src/zmu +src/zm_rtsp_server src/zoneminder-zmc.8 src/zoneminder-zmc.8.gz src/zoneminder-zmf.8 From 43dfeb5b847fa47fbe191de7e1a00b2fe16b6891 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 16:10:50 -0400 Subject: [PATCH 050/290] whitespace --- web/skins/classic/views/monitor.php | 32 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 327de5def..e7afc8cf6 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -21,44 +21,50 @@ require_once('includes/Server.php'); require_once('includes/Storage.php'); -if ( !canEdit('Monitors', empty($_REQUEST['mid'])?0:$_REQUEST['mid']) ) { +if (!canEdit('Monitors', empty($_REQUEST['mid'])?0:$_REQUEST['mid'])) { $view = 'error'; return; } $Server = null; -if ( defined('ZM_SERVER_ID') ) { +if (defined('ZM_SERVER_ID')) { $Server = dbFetchOne('SELECT * FROM Servers WHERE Id=?', NULL, array(ZM_SERVER_ID)); } -if ( !$Server ) { +if (!$Server) { $Server = array('Id' => ''); } $mid = null; $monitor = null; -if ( !empty($_REQUEST['mid']) ) { +if (!empty($_REQUEST['mid'])) { $mid = validInt($_REQUEST['mid']); $monitor = new ZM\Monitor($mid); - if ( $monitor and ZM_OPT_X10 ) - $x10Monitor = dbFetchOne('SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($mid)); + if ($monitor->Id()) { + if (ZM_OPT_X10) { + $x10Monitor = dbFetchOne('SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($mid)); + } + } else { + $monitor->Name(translate('Monitor').'-'.$mid); + $monitor->WebColour(random_colour()); + } } -if ( !$monitor ) { +if (!$monitor) { $monitor = new ZM\Monitor(); $monitor->Name(translate('Monitor').'-'.getTableAutoInc('Monitors')); $monitor->WebColour(random_colour()); } # end if $_REQUEST['mid'] -if ( isset($_REQUEST['dupId']) ) { +if (isset($_REQUEST['dupId'])) { $monitor = new ZM\Monitor($_REQUEST['dupId']); $monitor->GroupIds(); // have to load before we change the Id - if ( ZM_OPT_X10 ) + if (ZM_OPT_X10) $x10Monitor = dbFetchOne('SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId'])); $clonedName = $monitor->Name(); $monitor->Name('Clone of '.$monitor->Name()); $monitor->Id($mid); } -if ( ZM_OPT_X10 && empty($x10Monitor) ) { +if (ZM_OPT_X10 && empty($x10Monitor)) { $x10Monitor = array( 'Activation' => '', 'AlarmInput' => '', @@ -69,14 +75,14 @@ if ( ZM_OPT_X10 && empty($x10Monitor) ) { function fourcc($a, $b, $c, $d) { return ord($a) | (ord($b) << 8) | (ord($c) << 16) | (ord($d) << 24); } -if ( isset($_REQUEST['newMonitor']) ) { +if (isset($_REQUEST['newMonitor'])) { # Update the monitor object with whatever has been set so far. $monitor->set($_REQUEST['newMonitor']); - if ( ZM_OPT_X10 ) + if (ZM_OPT_X10) $newX10Monitor = $_REQUEST['newX10Monitor']; } else { - if ( ZM_OPT_X10 ) + if (ZM_OPT_X10) $newX10Monitor = $x10Monitor; } From f40e2be28a4238ce104c155a4fd71389233d9670 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 25 Sep 2021 20:54:35 -0400 Subject: [PATCH 051/290] Add an input for an Id to assign to the new monitor. List 10 available Ids. --- web/skins/classic/views/monitor.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index e7afc8cf6..05462ace9 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -355,6 +355,7 @@ $codecs = array( 'MJPEG' => translate('MJPEG'), ); +$monitors = dbFetchAll('SELECT Id, Name FROM Monitors ORDER BY Name,Sequence ASC'); $controls = ZM\Control::find(null, array('order'=>'lower(Name)')); xhtmlHeaders(__FILE__, translate('Monitor').' - '.validHtmlStr($monitor->Name())); @@ -452,6 +453,21 @@ foreach ( $tabs as $name=>$value ) { switch ( $name ) { case 'general' : { + if (!$monitor->Id()) { + $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); +?> + + +
+10 Available Ids: + + + +Id() ?> @@ -559,7 +575,6 @@ switch ( $name ) { Id() || ($monitor->Id()!= $linked_monitor['Id'])) && visibleMonitor($linked_monitor['Id']) ) { From ee609ad28bdeeec89f27b3c3c7d40f2fdfc040b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 26 Sep 2021 14:46:56 -0400 Subject: [PATCH 052/290] Further develop behavour when typing in text input for new manufacturer or model. If it already exists, select it. --- web/skins/classic/views/js/monitor.js | 49 ++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/js/monitor.js b/web/skins/classic/views/js/monitor.js index 44bcddb5b..88fae0a67 100644 --- a/web/skins/classic/views/js/monitor.js +++ b/web/skins/classic/views/js/monitor.js @@ -346,7 +346,7 @@ function getLocation() { } function populate_models(ManufacturerId) { - let dropdown = $j('[name="newMonitor[ModelId]"]'); + const dropdown = $j('[name="newMonitor[ModelId]"]'); if (!dropdown.length) { console.log("No element found for ModelId"); return; @@ -356,18 +356,22 @@ function populate_models(ManufacturerId) { dropdown.append(''); dropdown.prop('selectedIndex', 0); - // Populate dropdown with list of provinces - $j.getJSON(thisUrl+'?request=models&ManufacturerId='+ManufacturerId, function (data) { + 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('').attr('value', entry.Id).text(entry.Name)); - }); + $j.each(data.models, function(key, entry) { + dropdown.append($j('').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) { @@ -377,7 +381,7 @@ function ManufacturerId_onchange(ManufacturerId_select) { } else { ManufacturerId_select.form.elements['newMonitor[Manufacturer]'].style['display'] = 'inline'; // Set models dropdown to Unknown, text area visible - let ModelId_dropdown = $j('[name="newMonitor[ModelId]"]'); + const ModelId_dropdown = $j('[name="newMonitor[ModelId]"]'); ModelId_dropdown.empty(); ModelId_dropdown.append(''); ModelId_dropdown.prop('selectedIndex', 0); @@ -385,6 +389,31 @@ function ManufacturerId_onchange(ManufacturerId_select) { } } +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(); @@ -393,4 +422,8 @@ function ModelId_onchange(ModelId_select) { } } +function Model_onchange(input) { + select_by_value_case_insensitive(input.form.elements['newMonitor[ModelId]'], input.value); +} + window.addEventListener('DOMContentLoaded', initPage); From 1c01936f754b7cd4c72b9b01bb5ac9abef3f998d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 26 Sep 2021 14:47:29 -0400 Subject: [PATCH 053/290] add oninput methods to text inputs for new Manufacturer/Model --- web/skins/classic/views/monitor.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 05462ace9..f47e29912 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -482,7 +482,7 @@ switch ( $name ) { translate('unknown')); + $manufacturers = array(''=>translate('Unknown')); foreach ( ZM\Manufacturer::find( null, array('order'=>'lower(Name)')) as $Manufacturer ) { $manufacturers[$Manufacturer->Id()] = $Manufacturer->Name(); } @@ -492,6 +492,7 @@ switch ( $name ) { ManufacturerId() ? ' style="display:none"' : '' ?> + data-on-input-this="Manufacturer_onchange" /> @@ -500,7 +501,7 @@ switch ( $name ) { translate('unknown')); + $models = array(''=>translate('Unknown')); foreach ( ZM\Model::find(array('ManufacturerId'=>$monitor->ManufacturerId()), array('order'=>'lower(Name)')) as $Model ) { $models[$Model->Id()] = $Model->Name(); } @@ -509,7 +510,9 @@ switch ( $name ) { ?> ModelId() ? ' style="display:none"':'' ?>/> + value="Model()->Name() ?>"ModelId() ? ' style="display:none"':'' ?> + data-on-input-this="Model_onchange" + /> From fe734d4e1ec745aab4640de2f8f7ac3a413804de Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Sep 2021 10:56:50 -0400 Subject: [PATCH 054/290] Add Manufacturer and CameraModel hasOne relationships --- web/api/app/Model/Monitor.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/api/app/Model/Monitor.php b/web/api/app/Model/Monitor.php index de9a7685a..7a7d03588 100644 --- a/web/api/app/Model/Monitor.php +++ b/web/api/app/Model/Monitor.php @@ -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', ) ); From ee65d3e3dcf6f6e1a2b8fe8810cc2b7fa9ebbad6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Sep 2021 10:57:06 -0400 Subject: [PATCH 055/290] add cmaeramodels route --- web/api/app/Config/routes.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/api/app/Config/routes.php b/web/api/app/Config/routes.php index 6b3314d09..7c6352602 100644 --- a/web/api/app/Config/routes.php +++ b/web/api/app/Config/routes.php @@ -32,6 +32,7 @@ Router::mapResources('logs'); Router::mapResources('manufacturers'); Router::mapResources('models'); + Router::mapResources('cameramodels'); Router::mapResources('monitors'); Router::mapResources('servers'); Router::mapResources('states'); From 9cf4e892545e1460f7e5b4bc37e802a5cdebd76f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Sep 2021 11:03:16 -0400 Subject: [PATCH 056/290] add update to 1.37.3 --- db/zm_update-1.37.3.sql | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 db/zm_update-1.37.3.sql diff --git a/db/zm_update-1.37.3.sql b/db/zm_update-1.37.3.sql new file mode 100644 index 000000000..341c5e162 --- /dev/null +++ b/db/zm_update-1.37.3.sql @@ -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; From 8554ccd64982c8ff6ed101f7bc3182690565588c Mon Sep 17 00:00:00 2001 From: criadoperez Date: Wed, 29 Sep 2021 12:26:15 +0200 Subject: [PATCH 057/290] Added Debian 11 (bullseye) installation --- docs/installationguide/debian.rst | 86 +++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/docs/installationguide/debian.rst b/docs/installationguide/debian.rst index c6e0cebcf..15cc9660d 100644 --- a/docs/installationguide/debian.rst +++ b/docs/installationguide/debian.rst @@ -3,6 +3,92 @@ Debian .. contents:: +Easy Way: Debian 11 (Bullseye) +------------------------ + +This procedure will guide you through the installation of ZoneMinder on Debian 11 (Bullseye). + +**Step 1:** Setup Sudo (optional but recommended) + +By default Debian does not come with sudo, so you have to install it and configure it manually. +This step is optional but recommended and the following instructions assume that you have setup sudo. +If you prefer to setup ZoneMinder as root, do it at your own risk and adapt the following instructions accordingly. + +:: + + apt install sudo + usermod -a -G sudo + exit + +Now your terminal session is back under your normal user. You can check that +you are now part of the sudo group with the command ``groups``, "sudo" should +appear in the list. If not, run ``newgrp sudo`` and check again with ``groups``. + +**Step 2:** Update system and install zoneminder + +Run the following commands. + +:: + + sudo apt update + sudo apt upgrade + sudo apt install zoneminder + +**Step 3:** Initialize database + +Run the following commands. + +:: + + cat /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf + echo 'grant lock tables,alter,create,select,insert,update,delete,index on zm.* to 'zmuser'@localhost identified by "zmpass";' | sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql + +**Step 4:** Setup permissions for zm.conf + +To make sure zoneminder can read the configuration file, run the following command. + +:: + + sudo chgrp -c www-data /etc/zm/zm.conf + +**Step 5:** Edit Timezone in PHP + +Automated way: +:: + + sudo sed -i "s/;date.timezone =/date.timezone = $(sed 's/\//\\\//' /etc/timezone)/g" /etc/php/7.*/apache2/php.ini + +Manual way +:: + + sudo nano /etc/php/7.*/apache2/php.ini + +Search for [Date] (Ctrl + w then type Date and press Enter) and change +date.timezone for your time zone. Don't forget to remove the ; from in front +of date.timezone. + +:: + + [Date] + ; Defines the default timezone used by the date functions + ; http://php.net/date.timezone + date.timezone = America/New_York + +CTRL+o then [Enter] to save + +CTRL+x to exit + +**Step 6:** Reload Apache and start zoneminder + +Run the following commands. + +:: + + sudo systemctl reload apache2 + sudo systectl start zoneminder + +Congratulations! You should now be able to access zoneminder at ``http://yourhostname/zm`` + Easy Way: Debian Buster ------------------------ From 9f683c0c91f7c5f37d10f1bf502d499016a7bb84 Mon Sep 17 00:00:00 2001 From: criadoperez Date: Wed, 29 Sep 2021 14:14:25 +0200 Subject: [PATCH 058/290] Removed default-file parameter that is deprecated --- docs/installationguide/debian.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installationguide/debian.rst b/docs/installationguide/debian.rst index 15cc9660d..50173928f 100644 --- a/docs/installationguide/debian.rst +++ b/docs/installationguide/debian.rst @@ -40,8 +40,8 @@ Run the following commands. :: - cat /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf - echo 'grant lock tables,alter,create,select,insert,update,delete,index on zm.* to 'zmuser'@localhost identified by "zmpass";' | sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql + cat /usr/share/zoneminder/db/zm_create.sql | sudo mariadb + echo 'grant lock tables,alter,create,select,insert,update,delete,index on zm.* to 'zmuser'@localhost identified by "zmpass";' | sudo mariadb **Step 4:** Setup permissions for zm.conf From e462c231151ecb6044d747e3a1ad29ef948af3dd Mon Sep 17 00:00:00 2001 From: criadoperez Date: Wed, 29 Sep 2021 16:46:04 +0200 Subject: [PATCH 059/290] updated dlandon repository name --- docs/installationguide/easydocker.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/easydocker.rst b/docs/installationguide/easydocker.rst index 899ce0e5d..a7d37a9e5 100644 --- a/docs/installationguide/easydocker.rst +++ b/docs/installationguide/easydocker.rst @@ -2,7 +2,7 @@ An Easy To Use Docker Image =========================== If you are interested in trying out ZoneMinder quickly, user Dan Landon maintains an easy to use docker image for ZoneMinder. With a few simple configuration changes, it also provides complete Event Notification Server and Machine Learning hook support. Please follow instructions in his repostory. He maintains two repositories: -* If you want to run the latest stable release, please use his `zoneminder repository `__. +* If you want to run the latest stable release, please use his `zoneminder machine learning repository `__. * If you want to run the latest zoneminder master, please use his `zoneminder master repository `__. In both cases, instructions are provided in the repo README files. From 1e71300a3bee9cf8844c4cee6a75f4e0b2d130bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Criado-P=C3=A9rez?= Date: Thu, 30 Sep 2021 01:15:45 +0200 Subject: [PATCH 060/290] added Debian installation instructions --- docs/installationguide/debian.rst | 48 ++----------------------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/docs/installationguide/debian.rst b/docs/installationguide/debian.rst index 50173928f..f7325fe1f 100644 --- a/docs/installationguide/debian.rst +++ b/docs/installationguide/debian.rst @@ -32,18 +32,12 @@ Run the following commands. sudo apt update sudo apt upgrade + sudo apt install mariadb-server sudo apt install zoneminder -**Step 3:** Initialize database +When mariadb is installed for the first time, it doesn't add a password to the root user. Therefore, for security, it is recommended to run ``mysql secure installation``. -Run the following commands. - -:: - - cat /usr/share/zoneminder/db/zm_create.sql | sudo mariadb - echo 'grant lock tables,alter,create,select,insert,update,delete,index on zm.* to 'zmuser'@localhost identified by "zmpass";' | sudo mariadb - -**Step 4:** Setup permissions for zm.conf +**Step 3:** Setup permissions for zm.conf To make sure zoneminder can read the configuration file, run the following command. @@ -51,42 +45,6 @@ To make sure zoneminder can read the configuration file, run the following comma sudo chgrp -c www-data /etc/zm/zm.conf -**Step 5:** Edit Timezone in PHP - -Automated way: -:: - - sudo sed -i "s/;date.timezone =/date.timezone = $(sed 's/\//\\\//' /etc/timezone)/g" /etc/php/7.*/apache2/php.ini - -Manual way -:: - - sudo nano /etc/php/7.*/apache2/php.ini - -Search for [Date] (Ctrl + w then type Date and press Enter) and change -date.timezone for your time zone. Don't forget to remove the ; from in front -of date.timezone. - -:: - - [Date] - ; Defines the default timezone used by the date functions - ; http://php.net/date.timezone - date.timezone = America/New_York - -CTRL+o then [Enter] to save - -CTRL+x to exit - -**Step 6:** Reload Apache and start zoneminder - -Run the following commands. - -:: - - sudo systemctl reload apache2 - sudo systectl start zoneminder - Congratulations! You should now be able to access zoneminder at ``http://yourhostname/zm`` Easy Way: Debian Buster From d38a6adec44b17bb45628aa60475ea284138d6fb Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Tue, 12 Oct 2021 21:54:49 +0000 Subject: [PATCH 061/290] No behavior change. Added non-const versions of Image::Buffer and fixed a few places that were casting away the constness. --- src/zm_eventstream.cpp | 2 +- src/zm_image.h | 4 +++- src/zm_monitorstream.cpp | 2 +- src/zm_zone.cpp | 8 ++++---- src/zmbenchmark.cpp | 4 ++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 4bad2d61a..621970130 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -810,7 +810,7 @@ bool EventStream::sendFrame(Microseconds delta_us) { fputs("Content-Type: image/x-rgbz\r\n", stdout); break; case STREAM_RAW : - img_buffer = (uint8_t*)(send_image->Buffer()); + img_buffer = send_image->Buffer(); img_buffer_size = send_image->Size(); fputs("Content-Type: image/x-rgb\r\n", stdout); break; diff --git a/src/zm_image.h b/src/zm_image.h index 24626d789..74e5931eb 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -179,9 +179,11 @@ class Image { } } - /* Internal buffer should not be modified from functions outside of this class */ + inline uint8_t* Buffer() { return buffer; } inline const uint8_t* Buffer() const { return buffer; } + inline uint8_t* Buffer(unsigned int x, unsigned int y=0) { return &buffer[(y*linesize) + x*colours]; } inline const uint8_t* Buffer(unsigned int x, unsigned int y=0) const { return &buffer[(y*linesize) + x*colours]; } + /* Request writeable buffer */ uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder); // Is only acceptable on a pre-allocated buffer diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 067946eb7..5c32b8e05 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -422,7 +422,7 @@ bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) { break; case STREAM_RAW : fputs("Content-Type: image/x-rgb\r\n", stdout); - img_buffer = (uint8_t*)send_image->Buffer(); + img_buffer = send_image->Buffer(); img_buffer_size = send_image->Size(); break; case STREAM_ZIP : diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index bc7086614..f0c09ec78 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -206,7 +206,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { // Get the difference image Image *diff_image = image = new Image(*delta_image); int diff_width = diff_image->Width(); - uint8_t* diff_buff = (uint8_t*)diff_image->Buffer(); + uint8_t* diff_buff = diff_image->Buffer(); uint8_t* pdiff; unsigned int pixel_diff_count = 0; @@ -283,7 +283,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { int lo_x = ranges[y].lo_x; int hi_x = ranges[y].hi_x; - pdiff = (uint8_t*)diff_image->Buffer(lo_x, y); + pdiff = diff_image->Buffer(lo_x, y); for (int x = lo_x; x <= hi_x; x++, pdiff++) { if (*pdiff == kWhite) { @@ -366,7 +366,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { int lo_x = ranges[y].lo_x; int hi_x = ranges[y].hi_x; - pdiff = (uint8_t*)diff_image->Buffer(lo_x, y); + pdiff = diff_image->Buffer(lo_x, y); for (int x = lo_x; x <= hi_x; x++, pdiff++) { if (*pdiff == kWhite) { Debug(9, "Got white pixel at %d,%d (%p)", x, y, pdiff); @@ -980,7 +980,7 @@ void Zone::std_alarmedpixels( unsigned int hi_x = ranges[y].hi_x; Debug(7, "Checking line %d from %d -> %d", y, lo_x, hi_x); - uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer(lo_x, y); + uint8_t *pdiff = pdiff_image->Buffer(lo_x, y); const uint8_t *ppoly = ppoly_image->Buffer(lo_x, y); for ( unsigned int x = lo_x; x <= hi_x; x++, pdiff++, ppoly++ ) { diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index 244094a54..5e6b93e42 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -140,7 +140,7 @@ std::shared_ptr GenerateRandomImage( Image *image = new Image(width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE); // Set it to black initially. - memset((void *) image->Buffer(0, 0), 0, (size_t) image->LineSize() * (size_t) image->Height()); + memset(image->Buffer(0, 0), 0, (size_t) image->LineSize() * (size_t) image->Height()); // Now randomize the pixels inside a box. const int box_width = (width * change_box_percent) / 100; @@ -149,7 +149,7 @@ std::shared_ptr GenerateRandomImage( const int box_y = (int) ((uint64_t) mt_rand() * (height - box_height) / RAND_MAX); for (int y = 0 ; y < box_height ; y++) { - uint8_t *row = (uint8_t *) image->Buffer(box_x, box_y + y); + uint8_t *row = image->Buffer(box_x, box_y + y); for (int x = 0 ; x < box_width ; x++) { row[x] = (uint8_t) mt_rand(); } From 5970416f0ba8ff00e1aa112ae3f72882866555e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Flaget=20Aasen?= Date: Fri, 15 Oct 2021 00:25:51 +0200 Subject: [PATCH 062/290] Fix errors when converting man-pages with pod2man. Change unrecognised characters to corresponding ASCII value. pod2man generates errors when encountering non-ASCII characters. It correctly guesses UTF-8, but it still displays an error message in the produced man-page. --- onvif/proxy/lib/ONVIF/Analytics/Types/MotionInCells.pm | 2 +- .../lib/ONVIF/Device/Interfaces/Device/DevicePort.pm | 8 ++++---- onvif/proxy/lib/ONVIF/Device/Types/MotionInCells.pm | 2 +- onvif/proxy/lib/ONVIF/Media/Interfaces/Media/MediaPort.pm | 2 +- .../proxy/lib/ONVIF/Media/Types/FaultCodesOpenEnumType.pm | 2 +- onvif/proxy/lib/ONVIF/Media/Types/MotionInCells.pm | 2 +- .../lib/ONVIF/Media/Types/RelationshipTypeOpenEnum.pm | 2 +- onvif/proxy/lib/ONVIF/PTZ/Interfaces/PTZ/PTZPort.pm | 2 +- onvif/proxy/lib/ONVIF/PTZ/Types/FaultCodesOpenEnumType.pm | 2 +- onvif/proxy/lib/ONVIF/PTZ/Types/MotionInCells.pm | 2 +- .../proxy/lib/ONVIF/PTZ/Types/RelationshipTypeOpenEnum.pm | 2 +- onvif/proxy/lib/WSDiscovery10/Types/FaultCodeOpenType.pm | 2 +- .../proxy/lib/WSDiscovery10/Types/OpenRelationshipType.pm | 2 +- onvif/proxy/lib/WSDiscovery11/Types/FaultCodeOpenType.pm | 2 +- .../lib/WSDiscovery11/Types/FaultCodesOpenEnumType.pm | 2 +- .../lib/WSDiscovery11/Types/RelationshipTypeOpenEnum.pm | 2 +- .../WSNotification/Types/AbsoluteOrRelativeTimeType.pm | 2 +- .../lib/WSNotification/Types/FaultCodesOpenEnumType.pm | 2 +- .../lib/WSNotification/Types/RelationshipTypeOpenEnum.pm | 2 +- 19 files changed, 22 insertions(+), 22 deletions(-) diff --git a/onvif/proxy/lib/ONVIF/Analytics/Types/MotionInCells.pm b/onvif/proxy/lib/ONVIF/Analytics/Types/MotionInCells.pm index 89de61e18..b6a5a487a 100644 --- a/onvif/proxy/lib/ONVIF/Analytics/Types/MotionInCells.pm +++ b/onvif/proxy/lib/ONVIF/Analytics/Types/MotionInCells.pm @@ -147,7 +147,7 @@ This attribute is of type L object. @@ -3093,7 +3093,7 @@ Returns a L object. @@ -3288,7 +3288,7 @@ Returns a L object. @@ -3298,7 +3298,7 @@ Returns a L object. diff --git a/onvif/proxy/lib/ONVIF/Device/Types/MotionInCells.pm b/onvif/proxy/lib/ONVIF/Device/Types/MotionInCells.pm index a4bb4696b..87c17a350 100644 --- a/onvif/proxy/lib/ONVIF/Device/Types/MotionInCells.pm +++ b/onvif/proxy/lib/ONVIF/Device/Types/MotionInCells.pm @@ -147,7 +147,7 @@ This attribute is of type L object. diff --git a/onvif/proxy/lib/ONVIF/Media/Types/FaultCodesOpenEnumType.pm b/onvif/proxy/lib/ONVIF/Media/Types/FaultCodesOpenEnumType.pm index 12e921a67..f6bdde62a 100644 --- a/onvif/proxy/lib/ONVIF/Media/Types/FaultCodesOpenEnumType.pm +++ b/onvif/proxy/lib/ONVIF/Media/Types/FaultCodesOpenEnumType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/ONVIF/Media/Types/MotionInCells.pm b/onvif/proxy/lib/ONVIF/Media/Types/MotionInCells.pm index 687131675..e88c29862 100644 --- a/onvif/proxy/lib/ONVIF/Media/Types/MotionInCells.pm +++ b/onvif/proxy/lib/ONVIF/Media/Types/MotionInCells.pm @@ -147,7 +147,7 @@ This attribute is of type L or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/ONVIF/PTZ/Interfaces/PTZ/PTZPort.pm b/onvif/proxy/lib/ONVIF/PTZ/Interfaces/PTZ/PTZPort.pm index d1c5faa29..950c26344 100644 --- a/onvif/proxy/lib/ONVIF/PTZ/Interfaces/PTZ/PTZPort.pm +++ b/onvif/proxy/lib/ONVIF/PTZ/Interfaces/PTZ/PTZPort.pm @@ -987,7 +987,7 @@ Returns a L object. diff --git a/onvif/proxy/lib/ONVIF/PTZ/Types/FaultCodesOpenEnumType.pm b/onvif/proxy/lib/ONVIF/PTZ/Types/FaultCodesOpenEnumType.pm index e69cc37ad..e827b659b 100644 --- a/onvif/proxy/lib/ONVIF/PTZ/Types/FaultCodesOpenEnumType.pm +++ b/onvif/proxy/lib/ONVIF/PTZ/Types/FaultCodesOpenEnumType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/ONVIF/PTZ/Types/MotionInCells.pm b/onvif/proxy/lib/ONVIF/PTZ/Types/MotionInCells.pm index 8f68d1ef5..825f45ffa 100644 --- a/onvif/proxy/lib/ONVIF/PTZ/Types/MotionInCells.pm +++ b/onvif/proxy/lib/ONVIF/PTZ/Types/MotionInCells.pm @@ -147,7 +147,7 @@ This attribute is of type L or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSDiscovery10/Types/FaultCodeOpenType.pm b/onvif/proxy/lib/WSDiscovery10/Types/FaultCodeOpenType.pm index cd183e240..d89688025 100644 --- a/onvif/proxy/lib/WSDiscovery10/Types/FaultCodeOpenType.pm +++ b/onvif/proxy/lib/WSDiscovery10/Types/FaultCodeOpenType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSDiscovery10/Types/OpenRelationshipType.pm b/onvif/proxy/lib/WSDiscovery10/Types/OpenRelationshipType.pm index 45aab20e5..84f5985f8 100644 --- a/onvif/proxy/lib/WSDiscovery10/Types/OpenRelationshipType.pm +++ b/onvif/proxy/lib/WSDiscovery10/Types/OpenRelationshipType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSDiscovery11/Types/FaultCodeOpenType.pm b/onvif/proxy/lib/WSDiscovery11/Types/FaultCodeOpenType.pm index 52f5d2c8f..42fe97b83 100644 --- a/onvif/proxy/lib/WSDiscovery11/Types/FaultCodeOpenType.pm +++ b/onvif/proxy/lib/WSDiscovery11/Types/FaultCodeOpenType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSDiscovery11/Types/FaultCodesOpenEnumType.pm b/onvif/proxy/lib/WSDiscovery11/Types/FaultCodesOpenEnumType.pm index 89d8704e8..072948d96 100644 --- a/onvif/proxy/lib/WSDiscovery11/Types/FaultCodesOpenEnumType.pm +++ b/onvif/proxy/lib/WSDiscovery11/Types/FaultCodesOpenEnumType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSDiscovery11/Types/RelationshipTypeOpenEnum.pm b/onvif/proxy/lib/WSDiscovery11/Types/RelationshipTypeOpenEnum.pm index dc3e004c2..31c9df482 100644 --- a/onvif/proxy/lib/WSDiscovery11/Types/RelationshipTypeOpenEnum.pm +++ b/onvif/proxy/lib/WSDiscovery11/Types/RelationshipTypeOpenEnum.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSNotification/Types/AbsoluteOrRelativeTimeType.pm b/onvif/proxy/lib/WSNotification/Types/AbsoluteOrRelativeTimeType.pm index ac8dc805d..c80f98fe0 100644 --- a/onvif/proxy/lib/WSNotification/Types/AbsoluteOrRelativeTimeType.pm +++ b/onvif/proxy/lib/WSNotification/Types/AbsoluteOrRelativeTimeType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSNotification/Types/FaultCodesOpenEnumType.pm b/onvif/proxy/lib/WSNotification/Types/FaultCodesOpenEnumType.pm index 06e4df192..fae356a95 100644 --- a/onvif/proxy/lib/WSNotification/Types/FaultCodesOpenEnumType.pm +++ b/onvif/proxy/lib/WSNotification/Types/FaultCodesOpenEnumType.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." diff --git a/onvif/proxy/lib/WSNotification/Types/RelationshipTypeOpenEnum.pm b/onvif/proxy/lib/WSNotification/Types/RelationshipTypeOpenEnum.pm index e598093cb..0125e612c 100644 --- a/onvif/proxy/lib/WSNotification/Types/RelationshipTypeOpenEnum.pm +++ b/onvif/proxy/lib/WSNotification/Types/RelationshipTypeOpenEnum.pm @@ -44,7 +44,7 @@ not checked yet. The current implementation of union resorts to inheriting from the base type, which means (quoted from the XML Schema specs): "If the or -alternative is chosen, then the simple ur-type definition·." +alternative is chosen, then the simple ur-type definition." From f2281d10173f60139634eb5e5c870a12d6f27771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Flaget=20Aasen?= Date: Fri, 15 Oct 2021 07:41:28 +0200 Subject: [PATCH 063/290] Typos in documentation This is typos noticed by lintian. --- docs/faq.rst | 2 +- docs/userguide/definemonitor.rst | 8 ++++---- docs/userguide/filterevents.rst | 2 +- docs/userguide/gettingstarted.rst | 2 +- docs/userguide/options/options_users.rst | 4 ++-- .../Interfaces/WSDiscovery/WSDiscoveryPort.pm | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index dd0273667..f23fa2fc1 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -225,7 +225,7 @@ change the 3 to a 1 I can't see more than 6 monitors in montage on my browser --------------------------------------------------------- -Browsers such a Chrome and Safari only support upto 6 streams from the same domain. To work around that, take a look at the multi-port configuration discussed in the ``MIN_STREAMING_PORT`` configuration in :doc:`/userguide/options/options_network` +Browsers such a Chrome and Safari only support up to 6 streams from the same domain. To work around that, take a look at the multi-port configuration discussed in the ``MIN_STREAMING_PORT`` configuration in :doc:`/userguide/options/options_network` Why is ZoneMinder using so much CPU? --------------------------------------- diff --git a/docs/userguide/definemonitor.rst b/docs/userguide/definemonitor.rst index a5b622872..ab58b656c 100644 --- a/docs/userguide/definemonitor.rst +++ b/docs/userguide/definemonitor.rst @@ -86,7 +86,7 @@ Source Path Use this field to enter the full URL of the stream or file your camera supports. This is usually an RTSP url. There are several methods to learn this: * Check the documentation that came with your camera - * Look for your camera in the hardware compatibilty list in the `hardware compatibility wiki `__ + * Look for your camera in the hardware compatibility list in the `hardware compatibility wiki `__ * Try ZoneMinder's new ONVIF probe feature * Download and install the `ONVIF Device Manager `__ onto a Windows machine * Use Google to find third party sites, such as ispy, which document this information @@ -179,12 +179,12 @@ Storage Tab The storage section allows for each monitor to configure if and how video and audio are recorded. Save JPEGs - Records video in individual JPEG frames. Storing JPEG frames requires more storage space than h264 but it allows to view an event anytime while it is being recorded. + Records video in individual JPEG frames. Storing JPEG frames requires more storage space than h264 but it allows one to view an event anytime while it is being recorded. * Disabled – video is not recorded as JPEG frames. If this setting is selected, then "Video Writer" should be enabled otherwise there is no video recording at all. * Frames only – video is recorded in individual JPEG frames. - * Analysis images only (if available) – video is recorded in invidual JPEG frames with an overlay of the motion detection analysis information. Note that this overlay remains permanently visible in the frames. - * Frames + Analysis images (if available) – video is recorded twice, once as normal individual JPEG frames and once in invidual JPEG frames with analysis information overlaid. + * Analysis images only (if available) – video is recorded in individual JPEG frames with an overlay of the motion detection analysis information. Note that this overlay remains permanently visible in the frames. + * Frames + Analysis images (if available) – video is recorded twice, once as normal individual JPEG frames and once in individual JPEG frames with analysis information overlaid. Video Writer Records video in real video format. It provides much better compression results than saving JPEGs, thus longer video history can be stored. diff --git a/docs/userguide/filterevents.rst b/docs/userguide/filterevents.rst index b30a3185d..77f811fba 100644 --- a/docs/userguide/filterevents.rst +++ b/docs/userguide/filterevents.rst @@ -34,7 +34,7 @@ Here is what the filter window looks like * Update used disk space: calculates how much disk space is currently taken by the event and updates the db record. * Create video for all matches: creates a video file of all the events that match * Create video for all matches: ffmpeg will be used to create a video file (mp4) out of all the stored jpgs if using jpeg storage. - * Execute command on all matches: Allows you to execute any arbitrary command on the matched events. You can use replacement tokens as subsequent arguents to the command, the last argument will be the absolute path to the event, preceeded by replacement arguents. eg: /usr/bin/script.sh %MN% will excecute as /usr/bin/script.sh MonitorName /path/to/event. Please note that urls may contain characters like & that need quoting. So you may need to put quotes around them like /usr/bin/scrupt.sh "%MN%". + * Execute command on all matches: Allows you to execute any arbitrary command on the matched events. You can use replacement tokens as subsequent arguents to the command, the last argument will be the absolute path to the event, preceded by replacement arguents. eg: /usr/bin/script.sh %MN% will execute as /usr/bin/script.sh MonitorName /path/to/event. Please note that urls may contain characters like & that need quoting. So you may need to put quotes around them like /usr/bin/scrupt.sh "%MN%". * Delete all matches: Deletes all the matched events. * Email details of all matches: Sends an email to the configured address with details about the event. * Copy all matches: copies the event files to another location, specified in the Copy To dropdown. The other location must be setup in the Storage Tab under options. diff --git a/docs/userguide/gettingstarted.rst b/docs/userguide/gettingstarted.rst index 99f2ea4ba..61d4cb523 100644 --- a/docs/userguide/gettingstarted.rst +++ b/docs/userguide/gettingstarted.rst @@ -53,7 +53,7 @@ This screen is called the "console" screen in ZoneMinder and shows a summary of * **B**: This brings up a color coded log window that shows various system and component level logs. This window is useful if you are trying to diagnose issues. Refer to :doc:`logging`. * **C**: ZoneMinder allows you to group monitors for logical separation. This option lets you create new groups, associate monitors to them and edit/delete existing groups. * **D**: Filters are a powerful mechanism to perform actions when certain conditions are met. ZoneMinder comes with some preset filters that keep a tab of disk space and others. Many users create their own filters for more advanced actions like sending emails when certain events occur and more. Refer to :doc:`filterevents`. -* **E**: The Cycle option allows you to rotate between live views of each cofigured monitor. +* **E**: The Cycle option allows you to rotate between live views of each configured monitor. * **F**: The Montage option shows a collage of your monitors. You can customize them including moving them around. * **G**: Montage Review allows you to simultaneously view past events for different monitors. Note that this is a very resource intensive page and its performance will vary based on your system capabilities. * **H**: Audit Events Report is more of a power user feature. This option looks for recording gaps in events and recording issues in mp4 files. diff --git a/docs/userguide/options/options_users.rst b/docs/userguide/options/options_users.rst index def8744d7..4258c4ed0 100644 --- a/docs/userguide/options/options_users.rst +++ b/docs/userguide/options/options_users.rst @@ -30,7 +30,7 @@ This screen allows you to configure various permissions on a per user basis. The .. note:: if you are using zmNinja, users are required to have 'View' access to system because multi-server information is only available as part of this permission - Bandwidth - - Specifies the maximum bandwith that this user can configure (Low, Medium or High) + - Specifies the maximum bandwidth that this user can configure (Low, Medium or High) - API enabled - Specifies if the ZoneMinder API is enabled for this user (needs to be on, if you are using a mobile app such as zmNinja) @@ -42,4 +42,4 @@ Here is an example of a restricted user, for example: .. image:: images/Options_Users_Example.png -This user "home" is enabled, can view live streams and events, but only from "DoorBell" and "DeckCamera". This user also cannot control PTZ. \ No newline at end of file +This user "home" is enabled, can view live streams and events, but only from "DoorBell" and "DeckCamera". This user also cannot control PTZ. diff --git a/onvif/proxy/lib/WSDiscovery11/Interfaces/WSDiscovery/WSDiscoveryPort.pm b/onvif/proxy/lib/WSDiscovery11/Interfaces/WSDiscovery/WSDiscoveryPort.pm index a7dcd3532..0aa2a393c 100644 --- a/onvif/proxy/lib/WSDiscovery11/Interfaces/WSDiscovery/WSDiscoveryPort.pm +++ b/onvif/proxy/lib/WSDiscovery11/Interfaces/WSDiscovery/WSDiscoveryPort.pm @@ -100,7 +100,7 @@ of the corresponding class can be passed instead of the marked hash ref. You may pass any combination of objects, hash and list refs to these methods, as long as you meet the structure. -List items (i.e. multiple occurences) are not displayed in the synopsis. +List items (i.e. multiple occurrences) are not displayed in the synopsis. You may generally pass a list ref of hash refs (or objects) instead of a hash ref - this may result in invalid XML if used improperly, though. Note that SOAP::WSDL always expects list references at maximum depth position. From 3f6d6fe7a0bf21bf5462ca2934bec9284b6d3fb2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 17 Oct 2021 15:01:55 -0400 Subject: [PATCH 064/290] Improve debug logging of packetqueue cleaning --- src/zm_packetqueue.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 3cf77b866..93edd6da8 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -260,6 +260,7 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { zm_packet = *it; lp = new ZMLockedPacket(zm_packet); if (!lp->trylock()) { + Debug(3, "Failed locking packet %d", zm_packet->index); delete lp; break; } @@ -280,7 +281,7 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { next_front = it; } ++video_packets_to_delete; - Debug(4, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d", + Debug(3, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d", video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count); if (packet_counts[video_stream_id] - video_packets_to_delete <= pre_event_video_packet_count + tail_count) { break; @@ -289,7 +290,7 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { ++it; } // end while } // end if first packet not locked - Debug(1, "Resulting pointing at latest packet? %d, next front points to begin? %d", + Debug(1, "Resulting it pointing at latest packet? %d, next front points to begin? %d", ( *it == add_packet ), ( next_front == pktQueue.begin() ) ); From e1d49ea17288516b1b34980ba2fd614ddfee4292 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 17 Oct 2021 15:13:14 -0400 Subject: [PATCH 065/290] fix index -> image_index --- src/zm_packetqueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 93edd6da8..ceef421db 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -260,7 +260,7 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { zm_packet = *it; lp = new ZMLockedPacket(zm_packet); if (!lp->trylock()) { - Debug(3, "Failed locking packet %d", zm_packet->index); + Debug(3, "Failed locking packet %d", zm_packet->image_index); delete lp; break; } From 276add8ee47d578418e0b807a6d95fba7b1f582b Mon Sep 17 00:00:00 2001 From: makers-mark Date: Sun, 17 Oct 2021 16:03:52 -0400 Subject: [PATCH 066/290] Fix typo --- web/skins/classic/views/js/filter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index b59c68417..35254baf8 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -57,7 +57,7 @@ function validateForm(form) { form.elements['filter[AutoUnarchive]'].checked || form.elements['filter[UpdateDiskSpace]'].checked || form.elements['filter[AutoVideo]'].checked || - (form.elements['filter[AutoEmail]'].checked && form.elements['filter[AutoEmail]'].checked) || + (form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked) || (form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked) || form.elements['filter[AutoExecute]'].checked || form.elements['filter[AutoDelete]'].checked || From d1596dee02fa62e3138df3121a60d4c93823d444 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 17 Oct 2021 19:07:55 -0400 Subject: [PATCH 067/290] Fix removing uneeded checked --- web/skins/classic/views/js/filter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index b59c68417..35254baf8 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -57,7 +57,7 @@ function validateForm(form) { form.elements['filter[AutoUnarchive]'].checked || form.elements['filter[UpdateDiskSpace]'].checked || form.elements['filter[AutoVideo]'].checked || - (form.elements['filter[AutoEmail]'].checked && form.elements['filter[AutoEmail]'].checked) || + (form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked) || (form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked) || form.elements['filter[AutoExecute]'].checked || form.elements['filter[AutoDelete]'].checked || From 14e6d660e7c53afc079aeedfd6e293c9ec71da55 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 18 Oct 2021 20:15:02 -0700 Subject: [PATCH 068/290] Respect the encoder options for the header write. Fixes an issue where the encoder options were ignored in the passthrough case, because the options were free'ed and not re-initialized. --- src/zm_videostore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 1bd0724d5..6f76f3521 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -224,6 +224,8 @@ bool VideoStore::open() { ); video_out_codec = nullptr; } + av_dict_free(&opts); + av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); } // end if video_out_codec ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); @@ -231,7 +233,6 @@ bool VideoStore::open() { Error("Could not initialize stream parameteres"); } } // end if extradata_entry - av_dict_free(&opts); } else if (monitor->GetOptVideoWriter() == Monitor::ENCODE) { int wanted_codec = monitor->OutputCodec(); if (!wanted_codec) { From 16d0e269dfe182bfb5807ec248542d1eb12984a3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 16 Oct 2021 18:30:55 -0400 Subject: [PATCH 069/290] WHen saving v4l settings redirect back to watch instead of console. --- web/includes/actions/settings.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web/includes/actions/settings.php b/web/includes/actions/settings.php index a4aa1b489..710bfa641 100644 --- a/web/includes/actions/settings.php +++ b/web/includes/actions/settings.php @@ -20,18 +20,18 @@ // Monitor control actions, require a monitor id and control view permissions for that monitor -if ( empty($_REQUEST['mid']) ) { +if (empty($_REQUEST['mid'])) { ZM\Warning('Settings requires a monitor id'); return; } -if ( ! canView('Control', $_REQUEST['mid']) ) { +if (!canView('Control', $_REQUEST['mid'])) { ZM\Warning('Settings requires the Control permission'); return; } require_once('includes/Monitor.php'); $mid = validInt($_REQUEST['mid']); -if ( $action == 'settings' ) { +if ($action == 'settings') { $args = ' -m ' . escapeshellarg($mid); $args .= ' -B' . escapeshellarg($_REQUEST['newBrightness']); $args .= ' -C' . escapeshellarg($_REQUEST['newContrast']); @@ -45,5 +45,7 @@ if ( $action == 'settings' ) { dbQuery( 'UPDATE Monitors SET Brightness = ?, Contrast = ?, Hue = ?, Colour = ? WHERE Id = ?', array($brightness, $contrast, $hue, $colour, $mid)); + global $redirect; + $redirect = '?view=watch&mid='.$mid; } ?> From 6d7f752eb062387cbf70612dad54f297fac13055 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Oct 2021 13:04:49 -0400 Subject: [PATCH 070/290] Only record when in modect or nodect. Linked monitors would cause a monitor in monitor mode to record --- src/zm_monitor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index cd17f3fe0..e85330eb2 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2040,8 +2040,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score) { - + if (score and (function == MODECT or function == NODECT)) { 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() From 52f0240334549342126b904fed333725ffac2872 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Oct 2021 13:05:11 -0400 Subject: [PATCH 071/290] free and re-init opts as needed --- src/zm_videostore.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 6f76f3521..2b9f662e6 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -151,6 +151,7 @@ bool VideoStore::open() { Debug(3, "Encoder Option %s=%s", e->key, e->value); } } + av_dict_free(&opts); if (video_in_stream) { zm_dump_codecpar(video_in_stream->codecpar); @@ -184,6 +185,7 @@ bool VideoStore::open() { } } // end if orientation + av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); if (av_dict_get(opts, "new_extradata", nullptr, AV_DICT_MATCH_CASE)) { av_dict_set(&opts, "new_extradata", nullptr, 0); // Special flag to tell us to open a codec to get new extraflags to fix weird h265 @@ -224,14 +226,13 @@ bool VideoStore::open() { ); video_out_codec = nullptr; } - av_dict_free(&opts); - av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); } // end if video_out_codec ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); if (ret < 0) { Error("Could not initialize stream parameteres"); } + av_dict_free(&opts); } // end if extradata_entry } else if (monitor->GetOptVideoWriter() == Monitor::ENCODE) { int wanted_codec = monitor->OutputCodec(); @@ -486,6 +487,7 @@ bool VideoStore::open() { zm_dump_stream_format(oc, 0, 0, 1); if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); + av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); const AVDictionaryEntry *movflags_entry = av_dict_get(opts, "movflags", nullptr, AV_DICT_MATCH_CASE); if (!movflags_entry) { Debug(1, "setting movflags to frag_keyframe+empty_moov"); From ac15ea42cd4d46968eda06269fd61841d8bf0fd0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Oct 2021 14:34:17 -0400 Subject: [PATCH 072/290] enforce default action --- utils/do_debian_package.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index 2a4dd6989..6c8c06c00 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -230,12 +230,11 @@ rm .gitignore cd ../ -if [ !-e "$DIRECTORY.orig.tar.gz" ]; then -read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]" - if [[ $REPLY == [yY] ]]; then - - tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig -fi; +if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then + read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]" + if [[ "$REPLY" == "" || "$REPLY" == [yY] ]]; then + tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig + fi; fi; IFS=',' ;for DISTRO in `echo "$DISTROS"`; do From 4351f51929aa69989451373dcfd87477df2d3f28 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 20 Oct 2021 13:13:50 -0400 Subject: [PATCH 073/290] Fix logic ordering in 1.35.14 updated that moves columns from Monitors table to Monitor_Status --- db/zm_update-1.35.14.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql index daa8239ff..f3c8bf779 100644 --- a/db/zm_update-1.35.14.sql +++ b/db/zm_update-1.35.14.sql @@ -28,8 +28,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'TotalEvents' ) > 0, -"SELECT 'Column TotalEvents is already removed from Monitors'", -"ALTER TABLE `Monitors` DROP `TotalEvents`" +"ALTER TABLE `Monitors` DROP `TotalEvents`", +"SELECT 'Column TotalEvents is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -50,8 +50,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'TotalEventDiskSpace' ) > 0, -"SELECT 'Column TotalEventDiskSpace is already removed from Monitors'", -"ALTER TABLE `Monitors` DROP `TotalEventDiskSpace`" +"ALTER TABLE `Monitors` DROP `TotalEventDiskSpace`", +"SELECT 'Column TotalEventDiskSpace is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; From c6eedd434c9a174b03bdd204931a2bc44ec357e7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 22 Oct 2021 20:59:04 -0400 Subject: [PATCH 074/290] Make delete dialog disappear on success. Fixes #3377 --- web/skins/classic/views/js/event.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 727976e76..0cd770170 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -767,14 +767,15 @@ function handleClick(event) { // Manage the DELETE CONFIRMATION modal button function manageDelConfirmModalBtns() { document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) { - if ( !canEdit.Events ) { + if (!canEdit.Events) { enoperm(); return; } evt.preventDefault(); - $j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+eventData.Id) + $j.getJSON(thisUrl + '?request=event&task=delete&id='+eventData.Id) .done(function(data) { + $j('#deleteConfirm').modal('hide'); streamNext(true); }) .fail(logAjaxFail); From 9169da6963e3812eb5bd64c18298ec1d25084c4f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 11:09:06 -0400 Subject: [PATCH 075/290] Only start a transaction if we are not already in a transaction --- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index f3d750338..e54bb15ce 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -218,7 +218,7 @@ sub save { my $serial = eval '$'.$type.'::serial'; my @identified_by = eval '@'.$type.'::identified_by'; - my $ac = ZoneMinder::Database::start_transaction( $local_dbh ); + my $ac = ZoneMinder::Database::start_transaction( $local_dbh ) if $local_dbh->{AutoCommit}; if ( ! $serial ) { my $insert = $force_insert; my %serial = eval '%'.$type.'::serial'; @@ -234,8 +234,8 @@ $log->debug("No serial") if $debug; if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM `$table` WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) { $where =~ s/\?/\%s/g; $log->error("Error deleting: DELETE FROM $table WHERE " . sprintf($where, map { defined $_ ? $_ : 'undef' } ( @$self{@identified_by}) ).'):' . $local_dbh->errstr); - $local_dbh->rollback(); - ZoneMinder::Database::end_transaction( $local_dbh, $ac ); + $local_dbh->rollback() if $ac; + ZoneMinder::Database::end_transaction( $local_dbh, $ac ) if $ac; return $local_dbh->errstr; } elsif ( $debug ) { $log->debug("SQL succesful DELETE FROM $table WHERE $where"); @@ -267,8 +267,8 @@ $log->debug("No serial") if $debug; my $error = $local_dbh->errstr; $command =~ s/\?/\%s/g; $log->error('SQL statement execution failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $local_dbh->errstr); - $local_dbh->rollback(); - ZoneMinder::Database::end_transaction( $local_dbh, $ac ); + $local_dbh->rollback() if $ac; + ZoneMinder::Database::end_transaction( $local_dbh, $ac ) if $ac; return $error; } # end if if ( $debug or DEBUG_ALL ) { @@ -282,8 +282,8 @@ $log->debug("No serial") if $debug; my $error = $local_dbh->errstr; $command =~ s/\?/\%s/g; $log->error('SQL failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys, @$fields{@identified_by}}) ).'):' . $local_dbh->errstr); - $local_dbh->rollback(); - ZoneMinder::Database::end_transaction( $local_dbh, $ac ); + $local_dbh->rollback() if $ac; + ZoneMinder::Database::end_transaction( $local_dbh, $ac ) if $ac; return $error; } # end if if ( $debug or DEBUG_ALL ) { @@ -321,8 +321,8 @@ $log->debug("No serial") if $debug; $command =~ s/\?/\%s/g; my $error = $local_dbh->errstr; $log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $error); - $local_dbh->rollback(); - ZoneMinder::Database::end_transaction( $local_dbh, $ac ); + $local_dbh->rollback() if $ac; + ZoneMinder::Database::end_transaction( $local_dbh, $ac ) if $ac; return $error; } # end if if ( $debug or DEBUG_ALL ) { @@ -340,8 +340,8 @@ $log->debug("No serial") if $debug; my $error = $local_dbh->errstr; $command =~ s/\?/\%s/g; $log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}, @sql{@$fields{@identified_by}} ) ).'):' . $error) if $log; - $local_dbh->rollback(); - ZoneMinder::Database::end_transaction( $local_dbh, $ac ); + $local_dbh->rollback() if $ac; + ZoneMinder::Database::end_transaction( $local_dbh, $ac ) if $ac; return $error; } # end if if ( $debug or DEBUG_ALL ) { @@ -350,7 +350,7 @@ $log->debug("No serial") if $debug; } # end if } # end if } # end if - ZoneMinder::Database::end_transaction( $local_dbh, $ac ); + ZoneMinder::Database::end_transaction( $local_dbh, $ac ) if $ac; #$self->load(); #if ( $$fields{id} ) { #if ( ! $ZoneMinder::Object::cache{$type}{$$self{id}} ) { From 5e21d4833a2aa9c2de0760ce5909c03e32044961 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 11:09:29 -0400 Subject: [PATCH 076/290] Remove dead code, remove locking from CopyTo, put locking into MoveTo. --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 76 +++++++--------------- 1 file changed, 24 insertions(+), 52 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 48544a911..cc5722679 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -584,6 +584,7 @@ sub DiskSpace { return $_[0]{DiskSpace}; } +# Icon: I removed the locking from this. So we now have an assumption that the Event object is up to date. sub CopyTo { my ( $self, $NewStorage ) = @_; @@ -614,16 +615,12 @@ sub CopyTo { Debug("$NewPath is good"); } - $ZoneMinder::Database::dbh->begin_work(); - $self->lock_and_load(); # data is reloaded, so need to check that the move hasn't already happened. if ( $$self{StorageId} == $$NewStorage{Id} ) { - $ZoneMinder::Database::dbh->commit(); return 'Event has already been moved by someone else.'; } if ( $$OldStorage{Id} != $$self{StorageId} ) { - $ZoneMinder::Database::dbh->commit(); return 'Old Storage path changed, Event has moved somewhere else.'; } @@ -661,39 +658,21 @@ sub CopyTo { } my $event_path = $subpath.$self->RelativePath(); - if ( 0 ) { # Not neccessary - Debug("Making directory $event_path/"); - if ( !$bucket->add_key($event_path.'/', '') ) { - Warning("Unable to add key for $event_path/ :". $s3->err . ': '. $s3->errstr()); - } - } my @files = glob("$OldPath/*"); Debug("Files to move @files"); - foreach my $file ( @files ) { + foreach my $file (@files) { next if $file =~ /^\./; - ( $file ) = ( $file =~ /^(.*)$/ ); # De-taint + ($file) = ($file =~ /^(.*)$/); # De-taint my $starttime = [gettimeofday]; Debug("Moving file $file to $NewPath"); my $size = -s $file; - if ( ! $size ) { + if (!$size) { Info('Not moving file with 0 size'); } - if ( 0 ) { - my $file_contents = File::Slurp::read_file($file); - if ( ! $file_contents ) { - die 'Loaded empty file, but it had a size. Giving up'; - } - - my $filename = $event_path.'/'.File::Basename::basename($file); - if ( ! $bucket->add_key($filename, $file_contents) ) { - die "Unable to add key for $filename : ".$s3->err . ': ' . $s3->errstr; - } - } else { - my $filename = $event_path.'/'.File::Basename::basename($file); - if ( ! $bucket->add_key_filename($filename, $file) ) { - die "Unable to add key for $filename " . $s3->err . ': '. $s3->errstr; - } + my $filename = $event_path.'/'.File::Basename::basename($file); + if (!$bucket->add_key_filename($filename, $file)) { + die "Unable to add key for $filename " . $s3->err . ': '. $s3->errstr; } my $duration = tv_interval($starttime); @@ -704,16 +683,15 @@ sub CopyTo { }; Error($@) if $@; } else { - Error("Unable to parse S3 Url into it's component parts."); + Error('Unable to parse S3 Url into it\'s component parts.'); } - #die $@ if $@; } # end if Url } # end if s3 my $error = ''; - if ( !$moved ) { + if (!$moved) { File::Path::make_path($NewPath, {error => \my $err}); - if ( @$err ) { + if (@$err) { for my $diag (@$err) { my ($file, $message) = %$diag; next if $message eq 'File exists'; @@ -724,23 +702,16 @@ sub CopyTo { } } } - if ( $error ) { - $ZoneMinder::Database::dbh->commit(); - return $error; - } + return $error if $error; my @files = glob("$OldPath/*"); - if ( ! @files ) { - $ZoneMinder::Database::dbh->commit(); - return 'No files to move.'; - } + return 'No files to move.' if !@files; for my $file (@files) { next if $file =~ /^\./; - ( $file ) = ( $file =~ /^(.*)$/ ); # De-taint + ($file) = ($file =~ /^(.*)$/); # De-taint my $starttime = [gettimeofday]; - Debug("Moving file $file to $NewPath"); my $size = -s $file; - if ( ! File::Copy::copy( $file, $NewPath ) ) { + if (!File::Copy::copy($file, $NewPath)) { $error .= "Copy failed: for $file to $NewPath: $!"; last; } @@ -749,20 +720,21 @@ sub CopyTo { } # end foreach file. } # end if ! moved - if ( $error ) { - $ZoneMinder::Database::dbh->commit(); - return $error; - } + return $error if $error; } # end sub CopyTo sub MoveTo { - my ( $self, $NewStorage ) = @_; + my ($self, $NewStorage) = @_; - if ( !$self->canEdit() ) { + if (!$self->canEdit()) { Warning('No permission to move event.'); return 'No permission to move event.'; } + 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 + my $OldStorage = $self->Storage(undef); my $error = $self->CopyTo($NewStorage); @@ -772,11 +744,11 @@ sub MoveTo { $$self{StorageId} = $$NewStorage{Id}; $self->Storage($NewStorage); $error .= $self->save(); - if ( $error ) { - $ZoneMinder::Database::dbh->commit(); + if ($error) { + $ZoneMinder::Database::dbh->commit() if !$was_in_transaction; return $error; } - $ZoneMinder::Database::dbh->commit(); + $ZoneMinder::Database::dbh->commit() if !$was_in_transaction; $self->delete_files($OldStorage); return $error; } # end sub MoveTo From 8afed25d18067a2c86b0f2ddc47efcfd20d02a45 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 12:34:28 -0400 Subject: [PATCH 077/290] Use filter->sort_asc and sort_field which will use either the value specified in query, or defaults set in system. url params order and sort will override. --- web/ajax/events.php | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 562cce9c2..471f32664 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -6,28 +6,30 @@ $data = array(); // INITIALIZE AND CHECK SANITY // -if ( !canView('Events') ) $message = 'Insufficient permissions for user '.$user['Username']; +if (!canView('Events')) + $message = 'Insufficient permissions for user '.$user['Username'].'
'; -if ( empty($_REQUEST['task']) ) { - $message = 'Must specify a task'; +if (empty($_REQUEST['task'])) { + $message = 'Must specify a task
'; } else { $task = $_REQUEST['task']; } -if ( empty($_REQUEST['eids']) ) { - if ( isset($_REQUEST['task']) && $_REQUEST['task'] != 'query' ) $message = 'No event id(s) supplied'; +if (empty($_REQUEST['eids'])) { + if (isset($_REQUEST['task']) && $_REQUEST['task'] != 'query') + $message = 'No event id(s) supplied
'; } else { $eids = $_REQUEST['eids']; } -if ( $message ) { +if ($message) { ajaxError($message); return; } require_once('includes/Filter.php'); $filter = isset($_REQUEST['filter']) ? ZM\Filter::parse($_REQUEST['filter']) : new ZM\Filter(); -if ( $user['MonitorIds'] ) { +if ($user['MonitorIds']) { $filter = $filter->addTerm(array('cnj'=>'and', 'attr'=>'MonitorId', 'op'=>'IN', 'val'=>$user['MonitorIds'])); } @@ -39,10 +41,19 @@ $search = isset($_REQUEST['search']) ? $_REQUEST['search'] : ''; $advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'], JSON_OBJECT_AS_ARRAY) : array(); // Order specifies the sort direction, either asc or desc -$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; +$order = $filter->sort_asc() ? 'ASC' : 'DESC'; +if (isset($_REQUEST['order'])) { + if (strtolower($_REQUEST['order']) == 'asc')) { + $order = 'ASC'; + } else if (strtolower($_REQUEST['order']) == 'desc')) { + $order = 'DESC'; + } else { + Warning("Invalid value for order " . $_REQUEST['order']); + } +} // Sort specifies the name of the column to sort on -$sort = 'StartDateTime'; +$sort = $filter->sort_field(); if (isset($_REQUEST['sort'])) { $sort = $_REQUEST['sort']; if ($sort == 'EndDateTime') { From 0c222f66ee8be7f8f9a566653d2960a22ae08f59 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 12:34:51 -0400 Subject: [PATCH 078/290] Add sort_asc, sort_field and limit to the filter QueryString --- web/includes/Filter.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index 3578a1d62..a155d97a8 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -60,6 +60,9 @@ class Filter extends ZM_Object { foreach ( $this->FilterTerms() as $term ) { $this->_querystring .= $term->querystring($objectname, $separator); } # end foreach term + $this->_querystring .= $separator.urlencode($objectname.'[Query][sort_asc]').'='.$this->sort_asc(); + $this->_querystring .= $separator.urlencode($objectname.'[Query][sort_field]').'='.$this->sort_field(); + $this->_querystring .= $separator.urlencode($objectname.'[Query][limit]').'='.$this->limit(); if ( $this->Id() ) { $this->_querystring .= $separator.$objectname.urlencode('[Id]').'='.$this->Id(); } From 51e77438fa9d0ad91925f95e9874a03f41b230cd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 12:35:46 -0400 Subject: [PATCH 079/290] Add sort-name and sort-order to bootstrap table options. Also set data-remember-order=false. This allows orderings set by filters to work. Fixes #3348 --- web/skins/classic/views/events.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 52cb5c3f0..1c93e0b92 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -79,11 +79,14 @@ getBodyTopHTML(); data-cookie-id-table="zmEventsTable" data-cookie-expire="2y" data-click-to-select="true" - data-remember-order="true" + data-remember-order="false" data-show-columns="true" data-show-export="true" data-uncheckAll="true" data-toolbar="#toolbar" + data-sort-name="sort_field() ?>" + data-sort-order="sort_asc() ? 'asc' : 'desc' ?>" + data-server-sort="true" data-show-fullscreen="true" data-click-to-select="true" data-maintain-meta-data="true" From 1e38cf8bb7721b0cce7e3c323dd7b81a732eb949 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 16:40:21 -0400 Subject: [PATCH 080/290] Fix monitor type labels by adding an Unknown for entry 0. Implement Function_Strings. Fix decoding_enabled not being recalculated correctly because we havn't loaded savejpegs or videowriter yet. --- src/zm_monitor.cpp | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e85330eb2..93ae2d026 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -86,6 +86,7 @@ std::string load_monitor_sql = "`SignalCheckPoints`, `SignalCheckColour`, `Importance`-1 FROM `Monitors`"; std::string CameraType_Strings[] = { + "Unknown", "Local", "Remote", "File", @@ -93,10 +94,21 @@ std::string CameraType_Strings[] = { "LibVLC", "NVSOCKET", "CURL", - "VNC", + "VNC" +}; + +std::string Function_Strings[] = { + "Unknown", + "None", + "Monitor", + "Modect", + "Record", + "Mocord", + "Nodect" }; std::string State_Strings[] = { + "Unknown", "IDLE", "PREALARM", "ALARM", @@ -474,16 +486,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { function = (Function)atoi(dbrow[col]); col++; enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++; decoding_enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++; - decoding_enabled = !( - ( function == RECORD or function == NODECT ) - and - ( savejpegs == 0 ) - and - ( videowriter == PASSTHROUGH ) - and - !decoding_enabled - ); - Debug(1, "Decoding enabled: %d", decoding_enabled); + // See below after save_jpegs for a recalculation of decoding_enabled ReloadLinkedMonitors(dbrow[col]); col++; @@ -552,6 +555,17 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { videowriter = (VideoWriter)atoi(dbrow[col]); col++; encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + decoding_enabled = !( + ( function == RECORD or function == NODECT ) + and + ( savejpegs == 0 ) + and + ( videowriter == PASSTHROUGH ) + and + !decoding_enabled + ); + Debug(3, "Decoding enabled: %d function %d %s savejpegs %d videowriter %d", decoding_enabled, function, Function_Strings[function].c_str(), savejpegs, videowriter); + /*"`OutputCodec`, `Encoder`, `OutputContainer`, " */ output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; encoder = dbrow[col] ? dbrow[col] : ""; col++; From a55bd23bf65a1036c3770155513d3e7e2071dc0a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 24 Oct 2021 15:51:58 -0400 Subject: [PATCH 081/290] Add some extra parenthesis to make sure the logic works right --- web/skins/classic/views/js/watch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 8c8ea480d..aacad5126 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -945,7 +945,7 @@ function initPage() { }); // Only enable the settings button for local cameras - settingsBtn.prop('disabled', !(canView.Control && monitorType == 'Local')); + settingsBtn.prop('disabled', !(canView.Control && (monitorType == 'Local'))); // Init the bootstrap-table if (monitorType != 'WebSite') table.bootstrapTable({icons: icons}); From d56de57494e7e64dd49b4d80d460d46c6250d223 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 16:55:20 -0400 Subject: [PATCH 082/290] set vertical-align:top on monitor edit labels --- web/skins/classic/css/base/views/monitor.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/css/base/views/monitor.css b/web/skins/classic/css/base/views/monitor.css index 7fca80aac..f827af5ca 100644 --- a/web/skins/classic/css/base/views/monitor.css +++ b/web/skins/classic/css/base/views/monitor.css @@ -50,6 +50,7 @@ select.chosen { } tr td:first-child { min-width: 300px; + vertical-align: top; } .OutputContainer { display: none; From cebe86feb249c4397d87ebe04f21d932e7a87144 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Oct 2021 18:10:09 -0400 Subject: [PATCH 083/290] Make ZoneMinder::Control ingerit from Object. Make loadMonitor use MonitorId --- scripts/ZoneMinder/lib/ZoneMinder/Control.pm | 133 ++++++++++++++++--- 1 file changed, 113 insertions(+), 20 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm index feb12a0ca..e4d052700 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm @@ -29,6 +29,7 @@ use strict; use warnings; require ZoneMinder::Base; +require ZoneMinder::Object; require ZoneMinder::Monitor; our $VERSION = $ZoneMinder::Base::VERSION; @@ -42,24 +43,116 @@ our $VERSION = $ZoneMinder::Base::VERSION; use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); +use parent qw(ZoneMinder::Object); + +use vars qw/ $table $primary_key %fields $serial %defaults $debug/; +$table = 'Controls'; +$serial = $primary_key = 'Id'; +%fields = map { $_ => $_ } qw( + Id + Name + Type + Protocol + CanWake + CanSleep + CanReset + CanReboot + CanZoom + CanAutoZoom + CanZoomAbs + CanZoomRel + CanZoomCon + MinZoomRange + MaxZoomRange + MinZoomStep + MaxZoomStep + HasZoomSpeed + MinZoomSpeed + MaxZoomSpeed + CanFocus + CanAutoFocus + CanFocusAbs + CanFocusRel + CanFocusCon + MinFocusRange + MaxFocusRange + MinFocusStep + MaxFocusStep + HasFocusSpeed + MinFocusSpeed + MaxFocusSpeed + CanIris + CanAutoIris + CanIrisAbs + CanIrisRel + CanIrisCon + MinIrisRange + MaxIrisRange + MinIrisStep + MaxIrisStep + HasIrisSpeed + MinIrisSpeed + MaxIrisSpeed + CanGain + CanAutoGain + CanGainAbs + CanGainRel + CanGainCon + MinGainRange + MaxGainRange + MinGainStep + MaxGainStep + HasGainSpeed + MinGainSpeed + MaxGainSpeed + CanWhite + CanAutoWhite + CanWhiteAbs + CanWhiteRel + CanWhiteCon + MinWhiteRange + MaxWhiteRange + MinWhiteStep + MaxWhiteStep + HasWhiteSpeed + MinWhiteSpeed + MaxWhiteSpeed + HasPresets + NumPresets + HasHomePreset + CanSetPresets + CanMove + CanMoveDiag + CanMoveMap + CanMoveAbs + CanMoveRel + CanMoveCon + CanPan + MinPanRange + MaxPanRange + MinPanStep + MaxPanStep + HasPanSpeed + MinPanSpeed + MaxPanSpeed + HasTurboPan + TurboPanSpeed + CanTilt + MinTiltRange + MaxTiltRange + MinTiltStep + MaxTiltStep + HasTiltSpeed + MinTiltSpeed + MaxTiltSpeed + HasTurboTilt + TurboTiltSpeed + CanAutoScan + NumScanPaths + ); + our $AUTOLOAD; -sub new { - my $class = shift; - my $id = shift; - if ( !defined($id) ) { - Fatal('No monitor defined when invoking protocol '.$class); - } - my $self = {}; - $self->{name} = $class; - $self->{id} = $id; - bless($self, $class); - return $self; -} - -sub DESTROY { -} - sub AUTOLOAD { my $self = shift; my $class = ref($self); @@ -79,24 +172,24 @@ sub AUTOLOAD { sub getKey { my $self = shift; - return $self->{id}; + return $self->{Id}; } sub open { my $self = shift; - Fatal('No open method defined for protocol '.$self->{name}); + Fatal('No open method defined for protocol '.$self->{Protocol}); } sub close { my $self = shift; $self->{state} = 'closed'; - Debug('No close method defined for protocol '.$self->{name}); + Debug('No close method defined for protocol '.$self->{Protocol}); } sub loadMonitor { my $self = shift; if ( !$self->{Monitor} ) { - if ( !($self->{Monitor} = ZoneMinder::Monitor->find_one(Id=>$self->{id})) ) { + if ( !($self->{Monitor} = ZoneMinder::Monitor->find_one(Id=>$self->{MonitorId})) ) { Fatal('Monitor id '.$self->{id}.' not found'); } if ( defined($self->{Monitor}->{AutoStopTimeout}) ) { From c864d0765b0c32a0b30f5a8a6d7dfccf40b7d4fd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Oct 2021 18:10:39 -0400 Subject: [PATCH 084/290] Update, add url parsing to match other control scripts. Add getConfig and setConfig --- .../lib/ZoneMinder/Control/Vivotek_ePTZ.pm | 185 ++++++++++-------- 1 file changed, 99 insertions(+), 86 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm index 58ebe4c63..bcf1905c5 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm @@ -41,120 +41,133 @@ our @ISA = qw(ZoneMinder::Control); use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); +use ZoneMinder::General qw(:all); use Time::HiRes qw( usleep ); +use URI::Encode qw(uri_encode); -sub open -{ - my $self = shift; +our $REALM = ''; +our $PROTOCOL = 'http://'; +our $USERNAME = 'admin'; +our $PASSWORD = ''; +our $ADDRESS = ''; +our $BASE_URL = ''; - $self->loadMonitor(); - Debug( "Camera open" ); - use LWP::UserAgent; - $self->{ua} = LWP::UserAgent->new; - $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); +sub open { + my $self = shift; + $self->loadMonitor(); - $self->{state} = 'open'; + if (($self->{Monitor}->{ControlAddress} =~ /^(?https?:\/\/)?(?[^:@]+)?:?(?[^\/@]+)?@?(?
.*)$/)) { + $PROTOCOL = $+{PROTOCOL} if $+{PROTOCOL}; + $USERNAME = $+{USERNAME} if $+{USERNAME}; + $PASSWORD = $+{PASSWORD} if $+{PASSWORD}; + $ADDRESS = $+{ADDRESS} if $+{ADDRESS}; + } else { + Error('Failed to parse auth from address ' . $self->{Monitor}->{ControlAddress}); + $ADDRESS = $self->{Monitor}->{ControlAddress}; + } + if ( !($ADDRESS =~ /:/) ) { + Error('You generally need to also specify the port. I will append :80'); + $ADDRESS .= ':80'; + } + $BASE_URL = $PROTOCOL.($USERNAME?$USERNAME.':'.$PASSWORD.'@':'').$ADDRESS; + + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->agent( 'ZoneMinder Control Agent/'.ZoneMinder::Base::ZM_VERSION ); + $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; +sub close { + my $self = shift; + $self->{state} = 'closed'; } -sub printMsg -{ - my $msg = shift; - my $msg_len = length($msg); +sub sendCmd { + my ($self, $cmd, $speedcmd) = @_; - Debug( $msg."[".$msg_len."]" ); + $self->printMsg( $speedcmd, 'Tx' ); + $self->printMsg( $cmd, 'Tx' ); + + my $req = HTTP::Request->new( GET => $BASE_URL."/cgi-bin/camctrl/eCamCtrl.cgi?stream=0&$speedcmd&$cmd"); + my $res = $self->{ua}->request($req); + + if (!$res->is_success) { + Error('Request failed: '.$res->status_line().' (URI: '.$req->as_string().')'); + } + return $res->is_success; } -sub sendCmd -{ - my ($self, $cmd, $speedcmd) = @_; - - my $result = undef; - - printMsg( $speedcmd, "Tx" ); - printMsg( $cmd, "Tx" ); - - my $req = HTTP::Request->new( GET => "http://" . $self->{Monitor}->{ControlAddress} . "/cgi-bin/camctrl/eCamCtrl.cgi?stream=0&$speedcmd&$cmd" ); - my $res = $self->{ua}->request($req); - - if ( $res->is_success ) - { - $result = !undef; - } - else - { - Error( "Request failed: '" . $res->status_line() . "' (URI: '" . $req->as_string() . "')" ); - } - - return( $result ); +sub moveConUp { + my ($self, $params) = @_; + my $speed = 'speedtilt=' . ($params->{tiltspeed} - 6); + $self->sendCmd( 'move=up', $speed ); } -sub moveConUp -{ - my ($self, $params) = @_; - my $speed = 'speedtilt=' . ($params->{tiltspeed} - 6); - Debug( "Move Up" ); - $self->sendCmd( 'move=up', $speed ); +sub moveConDown { + my ($self, $params) = @_; + my $speed = 'speedtilt=' . ($params->{tiltspeed} - 6); + $self->sendCmd( 'move=down', $speed ); } -sub moveConDown -{ - my ($self, $params) = @_; - my $speed = 'speedtilt=' . ($params->{tiltspeed} - 6); - Debug( "Move Down" ); - $self->sendCmd( 'move=down', $speed ); +sub moveConLeft { + my ($self, $params) = @_; + my $speed = 'speedpan=-' . $params->{panspeed}; + $self->sendCmd( 'move=left', $speed ); } -sub moveConLeft -{ - my ($self, $params) = @_; - my $speed = 'speedpan=-' . $params->{panspeed}; - Debug( "Move Left" ); - $self->sendCmd( 'move=left', $speed ); +sub moveConRight { + my ($self, $params) = @_; + my $speed = 'speedpan=' . ($params->{panspeed} - 6); + $self->sendCmd( 'move=right', $speed ); } -sub moveConRight -{ - my ($self, $params) = @_; - my $speed = 'speedpan=' . ($params->{panspeed} - 6); - Debug( "Move Right" ); - $self->sendCmd( 'move=right', $speed ); +sub moveStop { + my $self = shift; + Debug( "Move Stop: not implemented" ); + # not implemented } -sub moveStop -{ - my $self = shift; - Debug( "Move Stop" ); - # not implemented +sub zoomConTele { + my ($self, $params) = @_; + my $speed = 'speedzoom=' . ($params->{speed} - 6); + $self->sendCmd( 'zoom=tele', $speed ); } -sub zoomConTele -{ - my ($self, $params) = @_; - my $speed = 'speedzoom=' . ($params->{speed} - 6); - Debug( "Zoom In" ); - $self->sendCmd( 'zoom=tele', $speed ); +sub zoomConWide { + my ($self, $params) = @_; + my $speed = 'speedzoom=' . ($params->{speed} - 6); + $self->sendCmd( 'zoom=wide', $speed ); } -sub zoomConWide -{ - my ($self, $params) = @_; - my $speed = 'speedzoom=' . ($params->{speed} - 6); - Debug( "Zoom Out" ); - $self->sendCmd( 'zoom=wide', $speed ); +sub reset { + my $self = shift; + $self->sendCmd( 'move=home' ); } -sub reset -{ - my $self = shift; - Debug( "Camera Reset" ); - $self->sendCmd( 'move=home' ); +sub get_config { + my $self = shift; + + my $url = $BASE_URL.'/cgi-bin/admin/lsctrl.cgi?cmd=queryStatus&retType=javascript'; + my $req = new HTTP::Request(GET => $url); + my $response = $self->{ua}->request($req); + if ( $response->is_success() ) { + my $resp = $response->decoded_content; + return ZoneMinder::General::parseNameEqualsValueToHash($resp); + } + Warn("Failed to get config from $url: " . $response->status_line()); + return; +} # end sub get_config + +sub set_config { + my $self = shift; + my $diff = shift; + + my $url = $BASE_URL.'/cgi-bin/'.$USERNAME.'/setparam.cgi?'. + join('&', map { $_.'='.uri_encode($$diff{$_}) } keys %$diff); + my $response = $self->{ua}->get($url); + Debug($response->content); + return $response->is_success(); } 1; From d62d88a0a3aaa639b551be50a91a292a45646124 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Oct 2021 18:11:34 -0400 Subject: [PATCH 085/290] add utility functions parseNameEqualsValueToHash and hash_diff --- scripts/ZoneMinder/lib/ZoneMinder/General.pm | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/General.pm b/scripts/ZoneMinder/lib/ZoneMinder/General.pm index d68967fa9..b14b08aae 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/General.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/General.pm @@ -31,6 +31,8 @@ our %EXPORT_TAGS = ( systemStatus packageControl daemonControl + parseNameEqualsValueToHash + hash_diff ) ] ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -534,6 +536,42 @@ sub jsonDecode { return $result; } +sub parseNameEqualsValueToHash { + my %settings; + foreach my $line ( split ( /\r?\n/, $_[0] ) ) { + next if ! $line; + next if ! ( $line =~ /=/ ); + my ($name, $value ) = split('=', $line); + $value =~ s/^'//; + $value =~ s/'$//; + $settings{$name} = defined $value ? $value : ''; + } + return %settings; +} + +sub hash_diff { + # assumes keys of second hash are all in the first hash + my ( $settings, $defaults ) = @_; + my %updates; + + foreach my $setting ( keys %{$settings} ) { + next if ! exists $$defaults{$setting}; + if ( + ($$settings{$setting} and ! $$defaults{$setting}) + or + (!$$settings{$setting} and $$defaults{$setting}) + or + ( + ($$settings{$setting} and $$defaults{$setting} and ( + $$settings{$setting} ne $$defaults{$setting})) + ) + ) { + $updates{$setting} = $$defaults{$setting}; + } + } # end foreach setting + return %updates; +} + sub packageControl { my $command = shift; my $string = $Config{ZM_PATH_BIN}.'/zmpkg.pl '.$command; @@ -598,6 +636,8 @@ of the ZoneMinder scripts packageControl daemonControl systemStatus + parseNameEqualsValueToHash + hash_diff ) ] From a2ec18be5ae44a3ec1d83b270133ff95e07bae97 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Oct 2021 18:15:03 -0400 Subject: [PATCH 086/290] Implement Control() function to implement the Protocol Specific Control object --- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index d01ef3455..899426164 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -36,6 +36,7 @@ require ZoneMinder::Server; require ZoneMinder::Memory; require ZoneMinder::Monitor_Status; require ZoneMinder::Zone; +use ZoneMinder::Logger qw(:all); #our @ISA = qw(Exporter ZoneMinder::Base); use parent qw(ZoneMinder::Object); @@ -313,6 +314,25 @@ sub resumeMotionDetection { return 1; } +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; + } + bless $Control, 'ZoneMinder::Control::'.$$Control{Protocol}; + $$Control{MonitorId} = $$self{Id}; + $$self{Control} = $Control; + } + } + return $$self{Control}; +} + 1; __END__ From a74b785d08f1333e64cd0b100b67bf241fc13fbd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Oct 2021 18:15:22 -0400 Subject: [PATCH 087/290] Move the protocol loading into the Monitor Object. --- scripts/zmcontrol.pl.in | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index 8a93a19a4..a9f26ac80 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -30,7 +30,6 @@ use autouse 'Pod::Usage'=>qw(pod2usage); use POSIX qw/strftime EPIPE EINTR/; use Socket; use Data::Dumper; -use Module::Load::Conditional qw{can_load}; use constant MAX_CONNECT_DELAY => 15; use constant MAX_COMMAND_WAIT => 1800; @@ -102,40 +101,21 @@ if ($options{command}) { } } else { # The server isn't there - my $monitor = zmDbGetMonitorAndControl($id); + require ZoneMinder::Monitor; + + my $monitor = ZoneMinder::Monitor->find_one(Id=>$id); Fatal("Unable to load control data for monitor $id") if !$monitor; - my $protocol = $monitor->{Protocol}; + my $control = $monitor->Control(); + + my $protocol = $control->{Protocol}; if (!$protocol) { Fatal('No protocol is set in monitor. Please edit the monitor, edit control type, select the control capability and fill in the Protocol field'); } - if (-x $protocol) { - # Protocol is actually a script! - # Holdover from previous versions - my $command .= $protocol.' '.$arg_string; - Debug($command); - - my $output = qx($command); - my $status = $? >> 8; - if ($status || logDebugging()) { - chomp($output); - Debug("Output: $output"); - } - if ($status) { - Error("Command '$command' exited with status: $status"); - exit($status); - } - exit(0); - } - Info("Starting control server $id/$protocol"); close(CLIENT); - if (!can_load(modules => {'ZoneMinder::Control::'.$protocol => undef})) { - Fatal("Can't load ZoneMinder::Control::$protocol\n$Module::Load::Conditional::ERROR"); - } - my $zm_terminate = 0; sub TermHandler { Info('Received TERM, exiting'); @@ -150,7 +130,6 @@ if ($options{command}) { $0 = $0.' --id '.$id; - my $control = ('ZoneMinder::Control::'.$protocol)->new($id); my $control_key = $control->getKey(); $control->loadMonitor(); From 6478999ecf4e936c3e614727b119205019288705 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 27 Oct 2021 12:21:03 -0400 Subject: [PATCH 088/290] Fix Event count subsitutions in emails because they are no longer in Monitor_Status. They are in Event_Summaries. So create a new object for them and use it. --- .../lib/ZoneMinder/Event_Summary.pm | 99 +++++++++++++++++++ scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm | 10 ++ .../lib/ZoneMinder/Monitor_Status.pm | 24 ----- scripts/zmfilter.pl.in | 18 ++-- 4 files changed, 118 insertions(+), 33 deletions(-) create mode 100644 scripts/ZoneMinder/lib/ZoneMinder/Event_Summary.pm diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event_Summary.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event_Summary.pm new file mode 100644 index 000000000..0086b5bac --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event_Summary.pm @@ -0,0 +1,99 @@ +# ========================================================================== +# +# ZoneMinder Event_Summary Module +# Copyright (C) 2020 ZoneMinder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# ========================================================================== +# +# This module contains the common definitions and functions used by the rest +# of the ZoneMinder scripts +# +package ZoneMinder::Event_Summary; + +use 5.006; +use strict; +use warnings; + +require ZoneMinder::Base; +require ZoneMinder::Object; + +#our @ISA = qw(Exporter ZoneMinder::Base); +use parent qw(ZoneMinder::Object); + +use vars qw/ $table $primary_key %fields $serial %defaults $debug/; +$table = 'Event_Summaries'; +$serial = $primary_key = 'MonitorId'; +%fields = map { $_ => $_ } qw( + MonitorId + TotalEvents + TotalEventDiskSpace + HourEvents + HourEventDiskSpace + DayEvents + DayEventDiskSpace + WeekEvents + WeekEventDiskSpace + MonthEvents + MonthEventDiskSpace + ArchivedEvents + ArchivedEventDiskSpace + ); + +%defaults = ( + TotalEvents => undef, + TotalEventDiskSpace => undef, + HourEvents => undef, + HourEventDiskSpace => undef, + DayEvents => undef, + DayEventDiskSpace => undef, + WeekEvents => undef, + WeekEventDiskSpace => undef, + MonthEvents => undef, + MonthEventDiskSpace => undef, + ArchivedEvents => undef, + ArchivedEventDiskSpace => undef, + ); + +sub Monitor { + return new ZoneMinder::Monitor( $_[0]{MonitorId} ); +} # end sub Monitor + +1; +__END__ + +=head1 NAME + +ZoneMinder::Event_Summary - Perl Class for Event Summaries + +=head1 SYNOPSIS + +use ZoneMinder::Event_Summary; + +=head1 AUTHOR + +Isaac Connor, Eisaac@zoneminder.comE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2001-2017 ZoneMinder LLC + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.8.3 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index 899426164..c5e09c137 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -35,6 +35,7 @@ require ZoneMinder::Storage; require ZoneMinder::Server; require ZoneMinder::Memory; require ZoneMinder::Monitor_Status; +require ZoneMinder::Event_Summary; require ZoneMinder::Zone; use ZoneMinder::Logger qw(:all); @@ -267,6 +268,15 @@ sub Status { return $$self{Status}; } +sub Event_Summary { + my $self = shift; + $$self{Event_Summary} = shift if @_; + if ( ! $$self{Event_Summary} ) { + $$self{Event_Summary} = ZoneMinder::Event_Summary->find_one(MonitorId=>$$self{Id}); + } + return $$self{Event_Summary}; +} + sub connect { my $self = shift; return ZoneMinder::Memory::zmMemVerify($self); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm index 9a9077653..1fafd3b0b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm @@ -43,18 +43,6 @@ $serial = $primary_key = 'MonitorId'; CaptureFPS AnalysisFPS CaptureBandwidth - TotalEvents - TotalEventDiskSpace - HourEvents - HourEventDiskSpace - DayEvents - DayEventDiskSpace - WeekEvents - WeekEventDiskSpace - MonthEvents - MonthEventDiskSpace - ArchivedEvents - ArchivedEventDiskSpace ); %defaults = ( @@ -62,18 +50,6 @@ $serial = $primary_key = 'MonitorId'; CaptureFPS => undef, AnalysisFPS => undef, CaptureBandwidth => undef, - TotalEvents => undef, - TotalEventDiskSpace => undef, - HourEvents => undef, - HourEventDiskSpace => undef, - DayEvents => undef, - DayEventDiskSpace => undef, - WeekEvents => undef, - WeekEventDiskSpace => undef, - MonthEvents => undef, - MonthEventDiskSpace => undef, - ArchivedEvents => undef, - ArchivedEventDiskSpace => undef, ); sub Monitor { diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 1e62cb229..61922771b 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -665,10 +665,10 @@ sub substituteTags { # We have a filter and an event, do we need any more # monitor information? my $need_monitor = $text =~ /%(?:MN|MET|MEH|MED|MEW|MEN|MEA)%/; - my $need_status = $text =~ /%(?:MET|MEH|MED|MEW|MEN|MEA)%/; + my $need_summary = $text =~ /%(?:MET|MEH|MED|MEW|MEN|MEA)%/; my $Monitor = $Event->Monitor() if $need_monitor; - my $Status = $Monitor->Status() if $need_status; + my $Summary = $Monitor->Event_Summary() if $need_summary; # Do we need the image information too? my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA|EIMOD|EIMODG)%/; @@ -692,19 +692,19 @@ sub substituteTags { } $rows ++; } - Debug("Frames: rows: $rows first alarm frame: $first_alarm_frame max_alaarm_frame: $max_alarm_frame, score: $max_alarm_score"); + Debug("Frames: rows: $rows first alarm frame: $first_alarm_frame max_alarm_frame: $max_alarm_frame, score: $max_alarm_score"); $sth->finish(); } my $url = $Config{ZM_URL}; $text =~ s/%ZP%/$url/g; $text =~ s/%MN%/$Monitor->{Name}/g; - $text =~ s/%MET%/$Status->{TotalEvents}/g; - $text =~ s/%MEH%/$Status->{HourEvents}/g; - $text =~ s/%MED%/$Status->{DayEvents}/g; - $text =~ s/%MEW%/$Status->{WeekEvents}/g; - $text =~ s/%MEM%/$Status->{MonthEvents}/g; - $text =~ s/%MEA%/$Status->{ArchivedEvents}/g; + $text =~ s/%MET%/$Summary->{TotalEvents}/g; + $text =~ s/%MEH%/$Summary->{HourEvents}/g; + $text =~ s/%MED%/$Summary->{DayEvents}/g; + $text =~ s/%MEW%/$Summary->{WeekEvents}/g; + $text =~ s/%MEM%/$Summary->{MonthEvents}/g; + $text =~ s/%MEA%/$Summary->{ArchivedEvents}/g; $text =~ s/%MP%/$url?view=watch&mid=$Event->{MonitorId}/g; $text =~ s/%MPS%/$url?view=watch&mid=$Event->{MonitorId}&mode=stream/g; $text =~ s/%MPI%/$url?view=watch&mid=$Event->{MonitorId}&mode=still/g; From 2bcad7bf5e7cb60b74037c837a6c856acc2bf93e Mon Sep 17 00:00:00 2001 From: SzymekCRX <59235537+SzymekCRX@users.noreply.github.com> Date: Thu, 28 Oct 2021 07:43:44 +0200 Subject: [PATCH 089/290] Critical bug in events.php Two extra brackets causes fatal error in Ajax request causing 500 HTTP error and problems with listing / deleting events --- web/ajax/events.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 471f32664..6d87da869 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -43,9 +43,9 @@ $advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'], // Order specifies the sort direction, either asc or desc $order = $filter->sort_asc() ? 'ASC' : 'DESC'; if (isset($_REQUEST['order'])) { - if (strtolower($_REQUEST['order']) == 'asc')) { + if (strtolower($_REQUEST['order']) == 'asc') { $order = 'ASC'; - } else if (strtolower($_REQUEST['order']) == 'desc')) { + } else if (strtolower($_REQUEST['order']) == 'desc') { $order = 'DESC'; } else { Warning("Invalid value for order " . $_REQUEST['order']); From 5955e4b410601571d422f420bc3cfffdb91972c0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 10:20:00 -0400 Subject: [PATCH 090/290] add licensing info for fontawesome. --- web/fonts/license.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/fonts/license.md b/web/fonts/license.md index 197f20b13..b56a5654f 100644 --- a/web/fonts/license.md +++ b/web/fonts/license.md @@ -1,6 +1,12 @@ ZoneMinder uses certain 3rd party media assets/libraries for UI display purposes. Their licenses are listed in this file +### Font Awesome icons + +Origin: http://fontawesome.io + +License: Font: SIL OFL 1.1, CSS: MIT License (http://fontawesome.io/license) + ### Material Design icons Origin: https://github.com/google/material-design-icons From 9fe2762bc898212376de551db3b51551d0da1f86 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 10:43:24 -0400 Subject: [PATCH 091/290] Add mp4 as an option for generated video and make it the default instead of avi --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index ff802dd15..48d494614 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -1064,7 +1064,7 @@ our @options = ( }, { name => 'ZM_FFMPEG_FORMATS', - default => 'mpg mpeg wmv asf avi* mov swf 3gp**', + default => 'mp4* mpg mpeg wmv asf avi mov swf 3gp**', description => 'Formats to allow for ffmpeg video generation', help => q` Ffmpeg can generate video in many different formats. This From c2bd2dc129dd8d12aacf24b65b401981376e4c65 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 10:44:46 -0400 Subject: [PATCH 092/290] Add a warning if db queue is larger than 10 --- src/zm_db.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index c6cc452b9..f659bb361 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -251,6 +251,13 @@ void zmDbQueue::process() { mCondition.wait(lock); } while (!mQueue.empty()) { + if (mQueue.size() > 10) { + Logger *log = Logger::fetch(); + Logger::Level db_level = log->databaseLevel(); + log->databaseLevel(Logger::NOLOG); + Warning("db queue size has grown larger than 10 entries"); + log->databaseLevel(db_level); + } std::string sql = mQueue.front(); mQueue.pop(); // My idea for leaving the locking around each sql statement is to allow From 2a160f045d35e238f34e4f9f05bfc1b02e4e9142 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 10:46:07 -0400 Subject: [PATCH 093/290] Put back generate video button --- web/skins/classic/views/event.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index a07c95042..81d4e97be 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -153,6 +153,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) ) download DefaultVideo() ? '' : 'style="display:none;"' ?> > + From 0c157904e6e44fdd43dee5604dde74e1e5b1d5e6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 10:46:26 -0400 Subject: [PATCH 094/290] add js to manage the generate video button --- web/skins/classic/views/js/event.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 0cd770170..050a78d59 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -708,7 +708,7 @@ function renameEvent() { } function exportEvent() { - window.location.assign('?view=export&eid='+eventData.Id); + window.location.assign('?view=export&eids[]='+eventData.Id); } function showEventFrames() { @@ -1016,7 +1016,13 @@ function initPage() { // Manage the EXPORT button bindButton('#exportBtn', 'click', null, function onExportClick(evt) { evt.preventDefault(); - window.location.assign('?view=export&eids[]='+eventData.Id); + exportEvent(); + }); + + // Manage the generateVideo button + bindButton('#videoBtn', 'click', null, function onExportClick(evt) { + evt.preventDefault(); + videoEvent(); }); // Manage the Event STATISTICS Button From fee69d3bc2e20585c47320cf17b5c63fb9ec7824 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 10:46:42 -0400 Subject: [PATCH 095/290] is no longer in existence --- web/skins/classic/views/video.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/video.php b/web/skins/classic/views/video.php index a4c01273f..597897936 100644 --- a/web/skins/classic/views/video.php +++ b/web/skins/classic/views/video.php @@ -102,7 +102,7 @@ $focusWindow = true; xhtmlHeaders(__FILE__, translate('Video')); ?> - +
From 644c6e6b41b37f5fb378526be4395fc89eca1ce1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 11:48:08 -0400 Subject: [PATCH 096/290] Just return the error --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index cc5722679..b740481eb 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -720,7 +720,7 @@ sub CopyTo { } # end foreach file. } # end if ! moved - return $error if $error; + return $error; } # end sub CopyTo sub MoveTo { From dedd755e5c63413017319dca7885e8439d4a1604 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 12:46:42 -0400 Subject: [PATCH 097/290] Handle auth to mysql problems more gracefully --- distros/ubuntu2004/zoneminder.postinst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/distros/ubuntu2004/zoneminder.postinst b/distros/ubuntu2004/zoneminder.postinst index 4be136a71..6f26bca24 100644 --- a/distros/ubuntu2004/zoneminder.postinst +++ b/distros/ubuntu2004/zoneminder.postinst @@ -5,6 +5,12 @@ set +e create_db () { echo "Checking for db" mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload + if [ $? -ne 0 ]; then + echo "Cannot talk to database. You will have to create the db manually with something like:"; + echo "cat /usr/share/zoneminder/db/zm_create.sql | mysql -u root"; + return; + fi + # test if database if already present... if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then echo "Creating zm db" From e063f0715fd35ec43a8feed4ea88c592bb79f218 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 13:00:41 -0400 Subject: [PATCH 098/290] reset starttime when changing events. Fixes super fast playback after switch to next event. Also, skip some unneeded calculations and logging. --- src/zm_eventstream.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 621970130..5e1ad605d 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -663,6 +663,7 @@ bool EventStream::checkEventLoaded() { else curr_frame_id = 1; Debug(2, "New frame id = %ld", curr_frame_id); + start = std::chrono::system_clock::now(); return true; } else { Debug(2, "No next event loaded using %s. Pausing", sql.c_str()); @@ -957,18 +958,20 @@ void EventStream::runStream() { static_cast(std::chrono::duration_cast(delta).count())); // if effective > base we should speed up frame delivery - delta = std::chrono::duration_cast((delta * base_fps) / effective_fps); - Debug(3, "delta %" PRIi64 " us = base_fps (%f) / effective_fps (%f)", + if (base_fps < effective_fps) { + delta = std::chrono::duration_cast((delta * base_fps) / effective_fps); + Debug(3, "delta %" PRIi64 " us = base_fps (%f) / effective_fps (%f)", static_cast(std::chrono::duration_cast(delta).count()), base_fps, effective_fps); - // but must not exceed maxfps - delta = std::max(delta, Microseconds(lround(Microseconds::period::den / maxfps))); - Debug(3, "delta %" PRIi64 " us = base_fps (%f) /effective_fps (%f) from 30fps", + // but must not exceed maxfps + delta = std::max(delta, Microseconds(lround(Microseconds::period::den / maxfps))); + Debug(3, "delta %" PRIi64 " us = base_fps (%f) / effective_fps (%f) from 30fps", static_cast(std::chrono::duration_cast(delta).count()), base_fps, effective_fps); + } // +/- 1? What if we are skipping frames? curr_frame_id += (replay_rate>0) ? frame_mod : -1*frame_mod; From b4314e5d46228cedd608e9048c001d4a24f67c31 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 15:11:42 -0400 Subject: [PATCH 099/290] Remove debugging --- web/skins/classic/views/js/filter.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index 35254baf8..5765a0e76 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -167,7 +167,6 @@ function submitToExport(element) { } function submitAction(button) { - console.log(button.value); var form = button.form; form.elements['action'].value = button.value; form.submit(); @@ -175,7 +174,6 @@ function submitAction(button) { function deleteFilter(element) { var form = element.form; - console.log(form); if (confirm(deleteSavedFilterString+" '"+form.elements['filter[Name]'].value+"'?")) { form.elements['action'].value = 'delete'; form.submit(); @@ -384,7 +382,6 @@ function debugFilter() { } function manageModalBtns(id) { - console.log(id); // Manage the CANCEL modal button var cancelBtn = document.getElementById(id+"CancelBtn"); if ( cancelBtn ) { From 4122ae99a5ecf552c9d4f3b0a5d96bed4cc53eb2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 12:03:58 -0400 Subject: [PATCH 100/290] add a comment about rollbacks --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index b740481eb..5f11b1ada 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -744,11 +744,11 @@ sub MoveTo { $$self{StorageId} = $$NewStorage{Id}; $self->Storage($NewStorage); $error .= $self->save(); - if ($error) { - $ZoneMinder::Database::dbh->commit() if !$was_in_transaction; - return $error; - } + + # Going to leave it to upper layout as to whether we rollback or not $ZoneMinder::Database::dbh->commit() if !$was_in_transaction; + return $error if $error; + $self->delete_files($OldStorage); return $error; } # end sub MoveTo From df88c5bbef9f58c7552abe5562cb32eaf16c315d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Oct 2021 15:26:12 -0400 Subject: [PATCH 101/290] layout->layer --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 5f11b1ada..0276af097 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -745,7 +745,7 @@ sub MoveTo { $self->Storage($NewStorage); $error .= $self->save(); - # Going to leave it to upper layout 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; From 1168fc52a5536f7d0d3c70ee58eac882a985398b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 29 Oct 2021 18:53:23 -0400 Subject: [PATCH 102/290] spacing and check for permission to view the specific event instead of events in general --- web/skins/classic/views/frame.php | 124 +++++++++++++++--------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index bdd2e1071..9931c910a 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -18,30 +18,28 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canView('Events') ) { - $view = 'error'; - return; -} - require_once('includes/Frame.php'); $eid = validInt($_REQUEST['eid']); $fid = empty($_REQUEST['fid']) ? 0 : validInt($_REQUEST['fid']); $Event = new ZM\Event($eid); +if (!$Event->canView()) { + $view = 'error'; + return; +} $Monitor = $Event->Monitor(); # This is kinda weird.. so if we pass fid=0 or some other non-integer, then it loads max score # perhaps we should consider being explicit, like fid = maxscore -if ( !empty($fid) ) { - $sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?'; - if ( !($frame = dbFetchOne($sql, NULL, array($eid, $fid))) ) +if (!empty($fid)) { + $sql = 'SELECT * FROM Frames WHERE EventId=? AND FrameId=?'; + if (!($frame = dbFetchOne($sql, NULL, array($eid, $fid)))) $frame = array('EventId'=>$eid, 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0); } else { - $frame = dbFetchOne('SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array($eid, $Event->MaxScore())); + $frame = dbFetchOne('SELECT * FROM Frames WHERE EventId=? AND Score=?', NULL, array($eid, $Event->MaxScore())); } $Frame = new ZM\Frame($frame); - $maxFid = $Event->Frames(); $firstFid = 1; @@ -51,11 +49,11 @@ $lastFid = $maxFid; $alarmFrame = ( $Frame->Type() == 'Alarm' ) ? 1 : 0; -if ( isset($_REQUEST['scale']) ) { +if (isset($_REQUEST['scale'])) { $scale = validNum($_REQUEST['scale']); -} else if ( isset($_COOKIE['zmWatchScale'.$Monitor->Id()]) ) { +} else if (isset($_COOKIE['zmWatchScale'.$Monitor->Id()])) { $scale = validNum($_COOKIE['zmWatchScale'.$Monitor->Id()]); -} else if ( isset($_COOKIE['zmWatchScale']) ) { +} else if (isset($_COOKIE['zmWatchScale'])) { $scale = validNum($_COOKIE['zmWatchScale']); } else { $scale = max(reScale(SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE); @@ -63,7 +61,7 @@ if ( isset($_REQUEST['scale']) ) { $scale = $scale ? $scale : 0; $imageData = $Event->getImageSrc($frame, $scale, 0); -if ( !$imageData ) { +if (!$imageData) { ZM\Error("No data found for Event $eid frame $fid"); $imageData = array(); } @@ -92,78 +90,80 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id().' - '.$Frame->Frame
- - - - + + + +

Id().'-'.$Frame->FrameId().' ('.$Frame->Score().')' ?>

-
'changeScale','id'=>'scale')); ?>
+
+ + 'changeScale','id'=>'scale')); ?> +
- From 224b34d69df71af704989fbd3cbd5dbacc970f24 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 29 Oct 2021 18:54:23 -0400 Subject: [PATCH 103/290] Send all stats rows instead of just 1. Handle receiving all rows, and don't list event id and frame id --- web/ajax/stats.php | 41 ++++++++---------- web/skins/classic/views/js/frame.js | 64 +++++++++++++++-------------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/web/ajax/stats.php b/web/ajax/stats.php index 06ce9d733..9226814b4 100644 --- a/web/ajax/stats.php +++ b/web/ajax/stats.php @@ -1,7 +1,6 @@ 1 ) { - $stat['BlobSizes'] = sprintf( "%d-%d (%d%%-%d%%)", $stat['MinBlobSize'], $stat['MaxBlobSize'], (100*$stat['MinBlobSize']/$stat['Area']), (100*$stat['MaxBlobSize']/$stat['Area']) ); + if ($stat['Blobs'] > 1) { + $stat['BlobSizes'] = sprintf('%d-%d (%d%%-%d%%)', $stat['MinBlobSize'], $stat['MaxBlobSize'], (100*$stat['MinBlobSize']/$stat['Area']), (100*$stat['MaxBlobSize']/$stat['Area'])); } else { - $stat['BlobSizes'] = sprintf( "%d (%d%%)", $stat['MinBlobSize'], 100*$stat['MinBlobSize']/$stat['Area'] ); + $stat['BlobSizes'] = sprintf('%d (%d%%)', $stat['MinBlobSize'], 100*$stat['MinBlobSize']/$stat['Area']); } - $stat['AlarmLimits'] = validHtmlStr($stat['MinX'].",".$stat['MinY']."-".$stat['MaxX'].",".$stat['MaxY']); - } - $data['raw'] = $stat; + $stat['AlarmLimits'] = validHtmlStr($stat['MinX'].','.$stat['MinY'].'-'.$stat['MaxX'].','.$stat['MaxY']); + $data['raw'][] = $stat; + } # end foreach stat/zone } else { $data['html'] = getStatsTableHTML($eid, $fid, $row); $data['id'] = '#contentStatsTable' .$row; diff --git a/web/skins/classic/views/js/frame.js b/web/skins/classic/views/js/frame.js index c10b6e87a..1040d5a48 100644 --- a/web/skins/classic/views/js/frame.js +++ b/web/skins/classic/views/js/frame.js @@ -12,10 +12,10 @@ function changeScale() { last: $j('#lastLink') }; - if ( img ) { + if (img) { var baseWidth = $j('#base_width').val(); var baseHeight = $j('#base_height').val(); - if ( ! parseInt(scale) ) { + if (!parseInt(scale)) { var newSize = scaleToFit(baseWidth, baseHeight, img, $j('#controls')); newWidth = newSize.width; newHeight = newSize.height; @@ -30,7 +30,7 @@ function changeScale() { } setCookie('zmWatchScale', scale, 3600); $j.each(controlsLinks, function(k, anchor) { //Make frames respect scale choices - if ( anchor ) { + if (anchor) { anchor.prop('href', anchor.prop('href').replace(/scale=.*&/, 'scale=' + scale + '&')); } }); @@ -39,11 +39,11 @@ function changeScale() { onStatsResize(newWidth); } -function getFrmStatsCookie() { +function getFrameStatsCookie() { var cookie = 'zmFrameStats'; var stats = getCookie(cookie); - if ( !stats ) { + if (!stats) { stats = 'on'; setCookie(cookie, stats, 10*365); } @@ -53,29 +53,33 @@ function getFrmStatsCookie() { function getStat(params) { $j.getJSON(thisUrl + '?view=request&request=stats&raw=true', params) .done(function(data) { - var stat = data.raw; + var stats = data.raw; + $j('#frameStatsTable').empty().append(''); - $j.each( statHeaderStrings, function( key ) { - var th = $j('').addClass('text-right').text(statHeaderStrings[key]); - var tdString; + for (const stat of stats) { + $j.each(statHeaderStrings, function(key) { + var th = $j('').addClass('text-right').text(statHeaderStrings[key]); + var tdString; - switch (stat ? key : 'n/a') { - case 'FrameId': - tdString = '' + stat[key] + ''; - break; - case 'n/a': - tdString = 'n/a'; - break; - default: - tdString = stat[key]; - } + switch (stat ? key : 'n/a') { + case 'FrameId': + case 'EventId': + //tdString = '' + stat[key] + ''; + break; + case 'n/a': + tdString = 'n/a'; + break; + default: + tdString = stat[key]; + } - var td = $j('').html(tdString); - var row = $j('').append(th, td); + var td = $j('').html(tdString); + var row = $j('').append(th, td); - $j('#frameStatsTable tbody').append(row); - }); + $j('#frameStatsTable tbody').append(row); + }); + } // end foreach stat }) .fail(logAjaxFail); } @@ -85,16 +89,16 @@ function onStatsResize(vidwidth) { var width = $j(window).width() - vidwidth; // Hide the stats table if we have run out of room to show it properly - if ( width < minWidth ) { + if (width < minWidth) { statsBtn.prop('disabled', true); - if ( table.is(':visible') ) { + if (table.is(':visible')) { table.toggle(false); wasHidden = true; } // Show the stats table if we hid it previously and sufficient room becomes available - } else if ( width >= minWidth ) { + } else if (width >= minWidth) { statsBtn.prop('disabled', false); - if ( !table.is(':visible') && wasHidden ) { + if (!table.is(':visible') && wasHidden) { table.toggle(true); wasHidden = false; } @@ -102,7 +106,7 @@ function onStatsResize(vidwidth) { } function initPage() { - if ( scale == '0' || scale == 'auto' ) changeScale(); + if (scale == '0' || scale == 'auto') changeScale(); // Don't enable the back button if there is no previous zm page to go back to backBtn.prop('disabled', !document.referrer.length); @@ -125,7 +129,7 @@ function initPage() { var cookie = 'zmFrameStats'; // Toggle the visiblity of the stats table and write an appropriate cookie - if ( table.is(':visible') ) { + if (table.is(':visible')) { setCookie(cookie, 'off', 10*365); table.toggle(false); } else { @@ -143,7 +147,7 @@ function initPage() { // Load the frame stats getStat({eid: eid, fid: fid}); - if ( getFrmStatsCookie() != 'on' ) { + if (getFrameStatsCookie() != 'on') { table.toggle(false); } else { onStatsResize($j('#base_width').val() * scale / SCALE_BASE); From 97164fd4d706c13be75d58c682d3cff89f51fffd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 31 Oct 2021 14:44:36 -0400 Subject: [PATCH 104/290] Fix use of thisUrl instead of monitorUrl when getting stream status. Fix changing stream image due to use of jquery. --- web/skins/classic/views/js/event.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 050a78d59..c449447f4 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -34,7 +34,7 @@ function streamReq(data) { data.view = 'request'; data.request = 'stream'; - $j.getJSON(thisUrl, data) + $j.getJSON(monitorUrl, data) .done(getCmdResponse) .fail(logAjaxFail); } @@ -300,7 +300,7 @@ function getCmdResponse(respObj, respText) { if (streamStatus.auth) { // Try to reload the image stream. - var streamImg = $j('#evtStream'); + var streamImg = document.getElementById('evtStream'); if (streamImg) { streamImg.src = streamImg.src.replace(/auth=\w+/i, 'auth='+streamStatus.auth); } From 0e3f694097be6674c81d4e4b5b03c5c0ae092f0f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 31 Oct 2021 15:19:26 -0400 Subject: [PATCH 105/290] Rename bootstrap with version so we don't have to cache bust it, so that .map loading works. --- web/skins/classic/includes/functions.php | 2 +- web/skins/classic/js/{bootstrap.js => bootstrap-4.5.0.js} | 0 .../classic/js/{bootstrap.min.js => bootstrap-4.5.0.min.js} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename web/skins/classic/js/{bootstrap.js => bootstrap-4.5.0.js} (100%) rename web/skins/classic/js/{bootstrap.min.js => bootstrap-4.5.0.min.js} (100%) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 1b01a73e8..c593601aa 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -916,7 +916,7 @@ function xhtmlFooter() { ?> - + Date: Tue, 2 Nov 2021 17:10:02 -0400 Subject: [PATCH 106/290] av_write_trailer can return a positive value which is not an error --- src/zm_videostore.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 2b9f662e6..ad401b22c 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -619,7 +619,8 @@ VideoStore::~VideoStore() { Debug(1, "Writing trailer"); /* Write the trailer before close */ - if (int rc = av_write_trailer(oc)) { + int rc; + if ((rc = av_write_trailer(oc)) < 0) { Error("Error writing trailer %s", av_err2str(rc)); } else { Debug(3, "Success Writing trailer"); @@ -629,7 +630,7 @@ VideoStore::~VideoStore() { if (!(out_format->flags & AVFMT_NOFILE)) { /* Close the out file. */ Debug(4, "Closing"); - if (int rc = avio_close(oc->pb)) { + if ((rc = avio_close(oc->pb)) < 0) { Error("Error closing avio %s", av_err2str(rc)); } } else { From 61f7989bec1b947960da5e29d2b63de37cbdfeb9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 31 Oct 2021 22:16:15 -0400 Subject: [PATCH 107/290] Actually report the # of dbQueue entries --- src/zm_db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index f659bb361..e3b737c07 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -255,7 +255,7 @@ void zmDbQueue::process() { Logger *log = Logger::fetch(); Logger::Level db_level = log->databaseLevel(); log->databaseLevel(Logger::NOLOG); - Warning("db queue size has grown larger than 10 entries"); + Warning("db queue size has grown larger %zu than 10 entries", mQueue.size()); log->databaseLevel(db_level); } std::string sql = mQueue.front(); From 86199718648f5cb929be2cb82c50772e0a28c7ef Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 2 Nov 2021 10:12:25 -0400 Subject: [PATCH 108/290] Better debug messages --- src/zm_event.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index adda18655..14b0fc9a3 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -479,7 +479,7 @@ void Event::AddFrame(Image *image, Debug(1, "Writing snapshot"); WriteFrameImage(image, timestamp, snapshot_file.c_str()); } else { - Debug(1, "Not Writing snapshot"); + Debug(1, "Not Writing snapshot because score %d > max %d", score, max_score); } // We are writing an Alarm frame @@ -491,7 +491,7 @@ void Event::AddFrame(Image *image, Debug(1, "Writing alarm image"); WriteFrameImage(image, timestamp, alarm_file.c_str()); } else { - Debug(1, "Not Writing alarm image"); + Debug(3, "Not Writing alarm image because alarm frame already written"); } if (alarm_image and (save_jpegs & 2)) { From 3208059040aee7c78152952033a660085cf6d75f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 2 Nov 2021 17:23:23 -0400 Subject: [PATCH 109/290] Fix event listing when not paginated. --- web/ajax/events.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 6d87da869..4e364242a 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -239,15 +239,17 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } # end if search $sql = 'SELECT ' .$col_str. ' FROM `Events` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order; - ZM\Debug('Calling the following sql query: ' .$sql); $filtered_rows = dbFetchAll($sql); - ZM\Debug('Have ' . count($filtered_rows) . ' events matching search filter.'); + ZM\Debug('Have ' . count($filtered_rows) . ' events matching search filter: '.$sql); } else { $filtered_rows = $unfiltered_rows; } # end if search_filter->terms() > 1 + if ($limit) + $filtered_rows = array_slice($filtered_rows, $offset, $limit); + $returned_rows = array(); - foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) { + foreach ($filtered_rows as $row) { $event = new ZM\Event($row); $scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width()); From 5f27c124c371f58ae09d12c2dc44219c05d57b37 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 2 Nov 2021 18:00:18 -0400 Subject: [PATCH 110/290] Ignore bootstrap-4.5.0.js --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 4682851df..91b0fd196 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,7 @@ web/api/lib web/includes/csrf/ web/js/videojs.zoomrotate.js -web/skins/classic/js/bootstrap.js +web/skins/classic/js/bootstrap-4.5.0.js web/skins/classic/js/chosen web/skins/classic/js/dateTimePicker web/skins/classic/js/jquery-*.js From a799eb3ad97e9b56687e83cf2181cad44ae128db Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Nov 2021 17:01:11 -0400 Subject: [PATCH 111/290] add function get_codec to return the codec used in the output mp4 --- src/zm_videostore.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 682fc147b..c73ed19db 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -111,6 +111,13 @@ class VideoStore { int writePacket(const std::shared_ptr &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 From 814eca2b4f036e66f447f1d19c7ece21b9c2e5a9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Nov 2021 17:02:02 -0400 Subject: [PATCH 112/290] Include the codec in the resulting mp4 filename. Remove event update setting the mp4 filename after insert, do it on event completing instead. Saves 1 db update. --- src/zm_event.cpp | 49 +++++++++++++++++++++++++++++------------------- src/zm_event.h | 7 ++++++- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 14b0fc9a3..442033c50 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -60,8 +60,8 @@ Event::Event( //snapshit_file(), //alarm_file(""), videoStore(nullptr), - //video_name(""), //video_file(""), + //video_path(""), last_db_frame(0), have_video_keyframe(false), //scheme @@ -104,6 +104,13 @@ 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(); + 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,7 +127,7 @@ Event::Event( state_id, monitor->getOrientation(), 0, - "", + video_incomplete_file.c_str(), save_jpegs, storage->SchemeString().c_str() ); @@ -178,24 +185,16 @@ Event::Event( } // end if ! setPath(Storage) Debug(1, "Using storage area at %s", path.c_str()); - video_name = ""; - snapshot_file = path + "/snapshot.jpg"; alarm_file = path + "/alarm.jpg"; - /* Save as video */ + video_incomplete_path = path + "/" + video_incomplete_file; - if ( monitor->GetOptVideoWriter() != 0 ) { - std::string container = monitor->OutputContainer(); - if ( container == "auto" || container == "" ) { - container = "mp4"; - } + if (monitor->GetOptVideoWriter() != 0) { + /* Save as video */ - video_name = stringtf("%" PRIu64 "-%s.%s", id, "video", container.c_str()); - video_file = path + "/" + video_name; - Debug(1, "Writing video file to %s", video_file.c_str()); videoStore = new VideoStore( - video_file.c_str(), + video_incomplete_path.c_str(), container.c_str(), monitor->GetVideoStream(), monitor->GetVideoCodecContext(), @@ -213,8 +212,10 @@ 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 } @@ -223,10 +224,18 @@ 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 +254,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(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(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 diff --git a/src/zm_event.h b/src/zm_event.h index 8b8e49322..611b2f716 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -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; From 93055f44e8bfd3a52d65fa348c5f1d1724091c83 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Nov 2021 17:03:29 -0400 Subject: [PATCH 113/290] Merge UpdateCaptureFPS and UpdateAnalysisFPS into UpdateFPS and call it from zmc after capture. --- src/zm_monitor.cpp | 80 +++++++++------------------------------------- src/zm_monitor.h | 3 +- src/zmc.cpp | 3 +- 3 files changed, 18 insertions(+), 68 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 93ae2d026..679ea27b7 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1656,7 +1656,7 @@ void Monitor::CheckAction() { } } -void Monitor::UpdateCaptureFPS() { +void Monitor::UpdateFPS() { if ( fps_report_interval and ( !(image_count%fps_report_interval) @@ -1675,82 +1675,35 @@ void Monitor::UpdateCaptureFPS() { uint32 new_camera_bytes = camera->Bytes(); uint32 new_capture_bandwidth = static_cast((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. @@ -2299,8 +2252,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); @@ -2585,7 +2536,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 +2575,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; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 92b724e65..56785405f 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -546,8 +546,7 @@ public: unsigned int GetLastWriteIndex() const; uint64_t GetLastEventId() const; double GetFPS() const; - void UpdateAnalysisFPS(); - void UpdateCaptureFPS(); + void UpdateFPS(); void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" ); void ForceAlarmOff(); void CancelForced(); diff --git a/src/zmc.cpp b/src/zmc.cpp index d974d1bec..68c6227af 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -268,7 +268,7 @@ int main(int argc, char *argv[]) { std::this_thread::sleep_for(sleep_time); } - if (zm_terminate){ + if (zm_terminate) { break; } @@ -308,6 +308,7 @@ int main(int argc, char *argv[]) { result = -1; break; } + monitors[i]->UpdateFPS(); // capture_delay is the amount of time we should sleep in useconds to achieve the desired framerate. Microseconds delay = (monitors[i]->GetState() == Monitor::ALARM) ? monitors[i]->GetAlarmCaptureDelay() From 0119ff46aaebf92881039800d953320f9d945fc8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Nov 2021 17:03:54 -0400 Subject: [PATCH 114/290] Remove redundant debug --- src/zm_image.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 2b7bc69e2..295426254 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -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) From 364ae03195b45812bd5844b0db54d3a0edffe276 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Nov 2021 17:04:13 -0400 Subject: [PATCH 115/290] Set zm_terminate on crash so that other threads exit instead of continuing --- src/zm_signal.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_signal.cpp b/src/zm_signal.cpp index 9a92b5eac..4107e96c8 100644 --- a/src/zm_signal.cpp +++ b/src/zm_signal.cpp @@ -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 From f737e3e945403019ee01efe1d85d1fa0eb1a135b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 6 Nov 2021 09:58:31 -0400 Subject: [PATCH 116/290] Only list available ids if there are some --- web/skins/classic/views/monitor.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 68ce50397..e4b2754ab 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -461,9 +461,12 @@ switch ( $name ) {
-10 Available Ids: - - + + Date: Sun, 7 Nov 2021 11:28:34 -0500 Subject: [PATCH 117/290] Pretty up the v4l field names --- web/ajax/modals/settings.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/web/ajax/modals/settings.php b/web/ajax/modals/settings.php index de42d6c87..e0bdf679c 100644 --- a/web/ajax/modals/settings.php +++ b/web/ajax/modals/settings.php @@ -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 ' - '.translate($setting_uc).' + '.$label.' '.$min.''.$max.' '; @@ -94,7 +99,7 @@ foreach ($ctls as $line) { if ($type == '(bool)') { echo ' - '.translate($setting_uc).' + '.$label.' '.html_radio('new'.$setting_uc, array('0'=>translate('True'), '1', translate('False')), $value, array('disabled'=>'disabled')).' @@ -102,14 +107,14 @@ foreach ($ctls as $line) { } else if ($type == '(int)') { echo ' - '.translate($setting_uc).' + '.$label.' '; } else { echo ' - '.translate($setting_uc).' + '.$label.' '.$value.' '; From 8c2dec03b6371aac74cca902608ac1ec4b1c981a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 09:48:57 -0500 Subject: [PATCH 118/290] Default to now instead of ... epoch? when endtime is null. Fixes video playing when event is incomplete --- src/zm_eventstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 5e1ad605d..af9dd8639 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -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(event_data->end_time - event_data->start_time); event_data->frames_duration = std::chrono::duration_cast(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0)); From ce81099489ccef7e3bfbadc35e792b479f057486 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:48:50 -0500 Subject: [PATCH 119/290] Report error if sql fails. Add check for access to specific event. --- web/ajax/events.php | 63 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 4e364242a..090fe476e 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -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; From e617eb86152b25a44c82b8a168833eb630a3292e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:49:01 -0500 Subject: [PATCH 120/290] Whitespace --- web/includes/database.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/includes/database.php b/web/includes/database.php index 34ea384fa..01926a26e 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -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; } From 7abbfc2fb54f8da9052baaab2c5107d2a0f5610d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:50:39 -0500 Subject: [PATCH 121/290] alert error message is an error is returned instead of rows --- web/skins/classic/views/js/events.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 9f6d34f75..6139ba3e4 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -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}); From 7aefd657c75b51a6e7c828d1e384ae23306639f7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:51:32 -0500 Subject: [PATCH 122/290] Cleanup and spacing. Rework last_motion_score to be a bit more efficient and use fewer lines. Fix case where MOCORD was not ending/starting event on alarm. --- src/zm_monitor.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 679ea27b7..cdf544682 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1862,8 +1862,6 @@ bool Monitor::Analyse() { Debug(3, "signal and active and modect"); Event::StringSet zoneSet; - int motion_score = last_motion_score; - if (analysis_fps_limit) { double capture_fps = get_capture_fps(); motion_frame_skip = capture_fps / analysis_fps_limit; @@ -1880,7 +1878,7 @@ bool Monitor::Analyse() { } else { Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image); // Get new score. - motion_score = DetectMotion(*(snap->image), zoneSet); + int motion_score = DetectMotion(*(snap->image), zoneSet); snap->zone_stats.reserve(zones.size()); for (const Zone &zone : zones) { @@ -1892,21 +1890,20 @@ bool Monitor::Analyse() { Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)", score, last_motion_score, motion_score); motion_frame_count += 1; - // Why are we updating the last_motion_score too? last_motion_score = motion_score; + if (motion_score) { + if (cause.length()) cause += ", "; + cause += MOTION_CAUSE; + noteSetMap[MOTION_CAUSE] = zoneSet; + } // end if motion_score } } else { Debug(1, "no image so skipping motion detection"); } // end if has image } else { - Debug(1, "Skipped motion detection last motion score was %d", motion_score); + Debug(1, "Skipped motion detection last motion score was %d", last_motion_score); } - if (motion_score) { - score += motion_score; - if (cause.length()) cause += ", "; - cause += MOTION_CAUSE; - noteSetMap[MOTION_CAUSE] = zoneSet; - } // end if motion_score + score += last_motion_score; } else { Debug(1, "Not Active(%d) enabled %d active %d doing motion detection: %d", Active(), enabled, shared_data->active, @@ -2007,7 +2004,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function == MODECT or function == NODECT)) { + if (score and (function == MODECT or function == NODECT or function == MOCORD)) { if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) { // If we should end then previous continuous event and start a new non-continuous event if (event && event->Frames() @@ -2142,7 +2139,8 @@ bool Monitor::Analyse() { shared_data->state = state = ((function != MOCORD) ? IDLE : TAPE); } else { Debug(1, - "State %s because image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + "State %d %s because analysis_image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + state, State_Strings[state].c_str(), analysis_image_count, last_alarm_count, @@ -2161,12 +2159,10 @@ bool Monitor::Analyse() { // Generate analysis images if necessary if ((savejpegs > 1) and snap->image) { for (const Zone &zone : zones) { - if (zone.Alarmed()) { - if (zone.AlarmImage()) { + if (zone.Alarmed() and zone.AlarmImage()) { if (!snap->analysis_image) snap->analysis_image = new Image(*(snap->image)); snap->analysis_image->Overlay(*(zone.AlarmImage())); - } } // end if zone is alarmed } // end foreach zone } // end if savejpegs From 38105c67968bb1c38b8bd24ed3308673f40ba96d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:54:33 -0500 Subject: [PATCH 123/290] Spacing --- src/zm_event.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 442033c50..d52f606a6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -323,32 +323,32 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) { bool update = false; //Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() ); - if ( newNoteSetMap.size() > 0 ) { - if ( noteSetMap.size() == 0 ) { + if (newNoteSetMap.size() > 0) { + if (noteSetMap.size() == 0) { noteSetMap = newNoteSetMap; update = true; } else { - for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); + for (StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); - ++newNoteSetMapIter ) { + ++newNoteSetMapIter) { const std::string &newNoteGroup = newNoteSetMapIter->first; const StringSet &newNoteSet = newNoteSetMapIter->second; //Info( "Got %d new strings", newNoteSet.size() ); - if ( newNoteSet.size() > 0 ) { + if (newNoteSet.size() > 0) { StringSetMap::iterator noteSetMapIter = noteSetMap.find(newNoteGroup); - if ( noteSetMapIter == noteSetMap.end() ) { - //Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() ); + if (noteSetMapIter == noteSetMap.end()) { + //Debug(3, "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size()); noteSetMap.insert(StringSetMap::value_type(newNoteGroup, newNoteSet)); update = true; } else { StringSet ¬eSet = noteSetMapIter->second; - //Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() ); - for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); + //Debug(3, "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size()); + for (StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); - ++newNoteSetIter ) { + ++newNoteSetIter) { const std::string &newNote = *newNoteSetIter; StringSet::iterator noteSetIter = noteSet.find(newNote); - if ( noteSetIter == noteSet.end() ) { + if (noteSetIter == noteSet.end()) { noteSet.insert(newNote); update = true; } From 5d23362ae02ca61ae4b8d3e5f62f81cb9ee7f8ce Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:59:05 -0500 Subject: [PATCH 124/290] use != Monitor instead of all the other cases --- src/zm_monitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index cdf544682..81eacc956 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2004,7 +2004,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function == MODECT or function == NODECT or function == MOCORD)) { + 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() From 66517218f1094ef22dad87abdec0f3878ac7092d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 14:00:04 -0500 Subject: [PATCH 125/290] Ignore versioned bootstrap --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 4682851df..91b0fd196 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,7 @@ web/api/lib web/includes/csrf/ web/js/videojs.zoomrotate.js -web/skins/classic/js/bootstrap.js +web/skins/classic/js/bootstrap-4.5.0.js web/skins/classic/js/chosen web/skins/classic/js/dateTimePicker web/skins/classic/js/jquery-*.js From 508be72e08cbfef15508208a0028c7fb97a31bf4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 15:49:25 -0500 Subject: [PATCH 126/290] Don't exit(0) on QUIT. Instead set zm_terminate=true so that all the cleanup routines run. --- src/zm_monitorstream.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 5c32b8e05..9bc04a311 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -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) { From 30d4900b45a56974614fc42cf5538311efb01cf1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 14:32:06 -0500 Subject: [PATCH 127/290] rough in fullscreen mode in watch view --- web/skins/classic/js/skin.js | 26 ++++++++++++++++++++++++++ web/skins/classic/views/js/watch.js | 5 +++++ web/skins/classic/views/watch.php | 3 +++ 3 files changed, 34 insertions(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index c7e2afedf..6ede08479 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -947,3 +947,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(); + } +} diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index aacad5126..5ba4b407c 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -970,5 +970,10 @@ function initPage() { }); } // initPage +function watchFullscreen() { + const content = document.getElementById('content'); + openFullscreen(content); +} + // Kick everything off $j(document).ready(initPage); diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index e1e54c3c7..beab28ac1 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -142,6 +142,9 @@ if ( $streamMode == 'jpeg' ) { + From f263da89867c4db9fab4deaf461894c15673190b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 16:12:39 -0500 Subject: [PATCH 128/290] Rough in fullscreen mode on montage --- web/skins/classic/views/js/montage.js | 5 +++++ web/skins/classic/views/montage.php | 3 +++ 2 files changed, 8 insertions(+) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 5312928a6..75b3a74d2 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -317,5 +317,10 @@ function initPage() { } selectLayout('#zmMontageLayout'); } + +function watchFullscreen() { + const content = document.getElementById('content'); + openFullscreen(content); +} // Kick everything off $j(document).ready(initPage); diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index 3256cfcc8..b0b10f190 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -206,6 +206,9 @@ if ( canView('System') ) {   +
From 44d88edbbbcbbd43ac6dcf7b35f8af7f2203d370 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 17:01:04 -0500 Subject: [PATCH 129/290] Fix some build warnings on arm --- src/zm_fifo.cpp | 4 ++-- src/zm_monitor.cpp | 22 +++++++++++----------- src/zm_packetqueue.cpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index 319c35c31..a999adc23 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -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 { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 81eacc956..b6e69a19f 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -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(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(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(mem_size), strerror(errno)); disconnect(); return false; } @@ -947,7 +947,7 @@ bool Monitor::connect() { map_fd = -1; return false; } else { - Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, mem_size); + Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, static_cast(mem_size)); close(map_fd); map_fd = -1; return false; @@ -959,18 +959,18 @@ bool Monitor::connect() { mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0); if (mem_ptr == MAP_FAILED) { if (errno == EAGAIN) { - Debug(1, "Unable to map file %s (%jd bytes) to locked memory, trying unlocked", mem_file.c_str(), mem_size); + Debug(1, "Unable to map file %s (%jd bytes) to locked memory, trying unlocked", mem_file.c_str(), static_cast(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(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(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(mem_size), strerror(errno), errno); close(map_fd); map_fd = -1; mem_ptr = nullptr; @@ -2310,7 +2310,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; @@ -2741,7 +2741,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) ) { @@ -2757,7 +2757,7 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const { typedef std::chrono::duration Centiseconds; Centiseconds centi_sec = std::chrono::duration_cast( ts_time.time_since_epoch() - std::chrono::duration_cast(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(centi_sec.count())); found_macro = true; break; } diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index ceef421db..509a25ee6 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -209,7 +209,7 @@ void PacketQueue::clearPackets(const std::shared_ptr &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 From 4c2d50c1f422a915f706b010aceda467f3afb667 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:18:58 -0500 Subject: [PATCH 130/290] implement UrlToZMS in Monitor --- web/includes/Monitor.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 027cafadd..788486b2e 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -495,6 +495,10 @@ class Monitor extends ZM_Object { return $this->Server()->UrlToIndex($port); } + public function UrlToZMS($port=null) { + return $this->Server()->UrlToZMS($port).'?mid='.$this->Id(); + } + public function sendControlCommand($command) { // command is generally a command option list like --command=blah but might be just the word quit From 474f65cff36354c5960e32070ae1d80d6a985556 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:20:19 -0500 Subject: [PATCH 131/290] Implement getElement, setScale in MonitorStream.js --- web/js/MonitorStream.js | 75 ++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index a10d90008..feb4b3611 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -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; } From b8f6172110ddee1ade30cdb0474d301ff01eb197 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:21:12 -0500 Subject: [PATCH 132/290] If no bottom element is specified, take the last child of content in scaleToFit --- web/skins/classic/js/skin.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 6ede08479..a12005e76 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -584,10 +584,21 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { $j(window).on('resize', endOfResize); //set delayed scaling when Scale to Fit is selected var ratio = baseWidth / baseHeight; var container = $j('#content'); + if (!container) { + console.error("No container found"); + return; + } + + if (!bottomEl || !bottomEl.length) { + bottomEl = $j(container[0].lastElementChild); + } + //console.log(bottomEl); var viewPort = $j(window); - // jquery does not provide a bottom offet, and offset dows not include margins. outerHeight true minus false gives total vertical margins. + // jquery does not provide a bottom offset, and offset does not include margins. outerHeight true minus false gives total vertical margins. var bottomLoc = bottomEl.offset().top + (bottomEl.outerHeight(true) - bottomEl.outerHeight()) + bottomEl.outerHeight(true); + //console.log("bottomLoc: " + bottomEl.offset().top + " + (" + bottomEl.outerHeight(true) + ' - ' + bottomEl.outerHeight() +') + '+bottomEl.outerHeight(true)); var newHeight = viewPort.height() - (bottomLoc - scaleEl.outerHeight(true)); + //console.log("newHeight = " + viewPort.height() +" - " + bottomLoc + ' - ' + scaleEl.outerHeight(true)); var newWidth = ratio * newHeight; if (newWidth > container.innerWidth()) { newWidth = container.innerWidth(); @@ -598,13 +609,15 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { return parseInt($j(this).val()); }).get(); scales.shift(); - var closest; + var closest = null; $j(scales).each(function() { //Set zms scale to nearest regular scale. Zoom does not like arbitrary scale values. if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) { closest = this.valueOf(); } }); - autoScale = closest; + if (closest) { + autoScale = closest; + } return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale}; } From 43c188626705adcbdde54d771242d030e13fd941 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:21:38 -0500 Subject: [PATCH 133/290] Put SCALE_BASE in skin.js.php as it is used in many places. --- web/skins/classic/js/skin.js.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/js/skin.js.php b/web/skins/classic/js/skin.js.php index 802a21095..87e08310e 100644 --- a/web/skins/classic/js/skin.js.php +++ b/web/skins/classic/js/skin.js.php @@ -54,6 +54,7 @@ foreach ( $perms as $perm ) { ?> var ANIMATE_THUMBS = ; +var SCALE_BASE = ; var refreshParent = Date: Wed, 10 Nov 2021 14:22:05 -0500 Subject: [PATCH 134/290] Implement Exit Fullscreen using same button --- web/skins/classic/views/js/watch.js | 14 ++++++++++++-- web/skins/classic/views/js/watch.js.php | 6 +++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 5ba4b407c..324e7f7e0 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -971,8 +971,18 @@ function initPage() { } // initPage function watchFullscreen() { - const content = document.getElementById('content'); - openFullscreen(content); + 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 diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index 258a1da73..5b4568dfc 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -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[] = ''; +var translate = { + "Fullscreen": "", + "Exit Fullscreen": "", +}; From ed84b5967156572ab4e26240ddcb5de2f9d39358 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:23:36 -0500 Subject: [PATCH 135/290] remove extra , --- web/ajax/event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 906fe255a..a0b9cb57a 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -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 { From 377219befea0ae4876c3367adb4d794126e3ede2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:12 -0500 Subject: [PATCH 136/290] Include url_to_zms in monitorData --- web/skins/classic/views/js/zone.js.php | 1 + web/skins/classic/views/js/zones.js.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/zone.js.php b/web/skins/classic/views/js/zone.js.php index fc6616327..37eb6db82 100644 --- a/web/skins/classic/views/js/zone.js.php +++ b/web/skins/classic/views/js/zone.js.php @@ -66,6 +66,7 @@ monitorData[monitorData.length] = { 'width': ViewWidth() ?>, 'height':ViewHeight() ?>, 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'url_to_zms': 'UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', 'type': 'Type() ?>', 'refresh': 'Refresh() ?>' }; diff --git a/web/skins/classic/views/js/zones.js.php b/web/skins/classic/views/js/zones.js.php index 180a19d81..338095552 100644 --- a/web/skins/classic/views/js/zones.js.php +++ b/web/skins/classic/views/js/zones.js.php @@ -9,6 +9,7 @@ monitorData[monitorData.length] = { 'width': ViewWidth() ?>, 'height':ViewHeight() ?>, 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'url_to_zms': 'UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', 'type': 'Type() ?>', 'refresh': 'Refresh() ?>' }; @@ -24,7 +25,7 @@ var STATE_TAPE = ; var stateStrings = new Array(); stateStrings[STATE_IDLE] = ""; -stateStrings[STATE_PREALARM] = ""; +stateStrings[STATE_PREALARM] = ""; stateStrings[STATE_ALARM] = ""; stateStrings[STATE_ALERT] = ""; stateStrings[STATE_TAPE] = ""; From 0732d4c1b3bd694ab6cb287ba70419b24686e914 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:29 -0500 Subject: [PATCH 137/290] setScale to auto --- web/skins/classic/views/js/zone.js | 1 + web/skins/classic/views/js/zones.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index 6282cbf8a..58c286b43 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -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); } diff --git a/web/skins/classic/views/js/zones.js b/web/skins/classic/views/js/zones.js index 0ad91942d..67dcb094a 100644 --- a/web/skins/classic/views/js/zones.js +++ b/web/skins/classic/views/js/zones.js @@ -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); From 2c0c257d76284b77277ef2941aef8e82b0e8a290 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:45 -0500 Subject: [PATCH 138/290] spacing --- web/skins/classic/views/zones.php | 67 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/web/skins/classic/views/zones.php b/web/skins/classic/views/zones.php index f457ad2fc..423326a98 100644 --- a/web/skins/classic/views/zones.php +++ b/web/skins/classic/views/zones.php @@ -80,15 +80,14 @@ xhtmlHeaders(__FILE__, translate('Zones')); Sorry, your browser does not support inline SVG @@ -96,37 +95,37 @@ xhtmlHeaders(__FILE__, translate('Zones'));  -  fps
-
- - - - - - - - - - - - - - - - - - - -
 / ViewWidth()*$monitor->ViewHeight()) ) ?> disabled="disabled"/>
-
- - -
-
-
+
+ + + + + + + + + + + + + + + + + + + +
 / ViewWidth()*$monitor->ViewHeight()) ) ?> disabled="disabled"/>
+
+ + +
+
+
Date: Wed, 10 Nov 2021 16:53:07 -0500 Subject: [PATCH 139/290] Use event->StartTime instead of GetVideoWriterStartTime. Add some parenthesis to make logic clearer and add more info to debug statements --- src/zm_monitor.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index b6e69a19f..d808ddba0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1916,7 +1916,7 @@ bool Monitor::Analyse() { if (event) { Debug(2, "Have event %" PRIu64 " in record", event->Id()); - if (section_length != Seconds(0) && (timestamp - GetVideoWriterStartTime() >= section_length) + if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length) && ((function == MOCORD && event_close_mode != CLOSE_TIME) || (function == RECORD && event_close_mode == CLOSE_TIME) || std::chrono::duration_cast(timestamp.time_since_epoch()) % section_length == Seconds(0))) { @@ -1925,8 +1925,8 @@ bool Monitor::Analyse() { image_count, event->Id(), static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), - static_cast(std::chrono::duration_cast(GetVideoWriterStartTime().time_since_epoch()).count()), - static_cast(std::chrono::duration_cast(timestamp - GetVideoWriterStartTime()).count()), + static_cast(std::chrono::duration_cast(event->StartTime().time_since_epoch()).count()), + static_cast(std::chrono::duration_cast(timestamp - event->StartTime()).count()), static_cast(Seconds(section_length).count())); closeEvent(); } // end if section_length @@ -2009,21 +2009,22 @@ bool Monitor::Analyse() { // 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(std::chrono::duration_cast(timestamp - GetVideoWriterStartTime()).count()), - static_cast(Seconds(min_section_length).count())); + static_cast(std::chrono::duration_cast(timestamp - event->StartTime()).count()), + static_cast(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 @@ -2120,8 +2121,10 @@ bool Monitor::Analyse() { Info("%s: %03d - Gone into alert state", name.c_str(), analysis_image_count); shared_data->state = state = ALERT; } else if (state == ALERT) { - if (analysis_image_count - last_alarm_count > post_event_count - && timestamp - GetVideoWriterStartTime() >= min_section_length) { + if ( + ((analysis_image_count - last_alarm_count) > post_event_count) + && + ((timestamp - event->StartTime()) >= min_section_length)) { Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name.c_str(), analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames()); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) @@ -2168,7 +2171,6 @@ bool Monitor::Analyse() { } // 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) { @@ -2183,7 +2185,7 @@ bool Monitor::Analyse() { if (event) { if (noteSetMap.size() > 0) event->updateNotes(noteSetMap); - if (section_length != Seconds(0) && (timestamp - GetVideoWriterStartTime() >= section_length)) { + if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length)) { Warning("%s: %03d - event %" PRIu64 ", has exceeded desired section length. %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64, name.c_str(), analysis_image_count, event->Id(), static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), From 8d85d0f6402d43959e223234f798a969512af16e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 16:53:29 -0500 Subject: [PATCH 140/290] Make state enum start at 0 as we are indexing into an array for StateStrings --- src/zm_monitor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 56785405f..5b9a2ce46 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -100,7 +100,7 @@ public: } Deinterlace; typedef enum { - UNKNOWN=-1, + UNKNOWN, IDLE, PREALARM, ALARM, From 721769993b746f04f0205ca6fe854574dff855c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 17:05:46 -0500 Subject: [PATCH 141/290] Set to never timeout while generating video --- web/skins/classic/views/js/video.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/skins/classic/views/js/video.js b/web/skins/classic/views/js/video.js index 970119f4f..c764f33b5 100644 --- a/web/skins/classic/views/js/video.js +++ b/web/skins/classic/views/js/video.js @@ -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) From 9d71f1192a0dac30f273942bbd062b453349e478 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 29 Sep 2021 09:30:04 -0400 Subject: [PATCH 142/290] merge manufacturer update into existing zm_update-1.37.2 and then move it to .in --- db/manufacturers.sql | 19 ----------------- db/zm_update-1.37.3.sql | 47 ----------------------------------------- 2 files changed, 66 deletions(-) delete mode 100644 db/zm_update-1.37.3.sql diff --git a/db/manufacturers.sql b/db/manufacturers.sql index eaee2630c..be15f9c01 100644 --- a/db/manufacturers.sql +++ b/db/manufacturers.sql @@ -1,23 +1,4 @@ INSERT INTO Manufacturers VALUES (1, 'Acti'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A21'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A23'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A24'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A28'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A31'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A310'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A311'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A32'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A41'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A415'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A416'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A418'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A42'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A421'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A43'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A45'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A46'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A48'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A74'); INSERT INTO Manufacturers VALUES (2, 'Amcrest'); INSERT INTO Manufacturers VALUES (3, 'Airlink101'); INSERT INTO Manufacturers VALUES (4, 'Arecont Vision'); diff --git a/db/zm_update-1.37.3.sql b/db/zm_update-1.37.3.sql deleted file mode 100644 index 341c5e162..000000000 --- a/db/zm_update-1.37.3.sql +++ /dev/null @@ -1,47 +0,0 @@ -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; From dc756ad670373e7cbe6dd3201fabbb44f1c922a3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 19:20:39 -0500 Subject: [PATCH 143/290] add back update for Manufacturers and Models --- db/zm_update-1.37.3.sql | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 db/zm_update-1.37.3.sql diff --git a/db/zm_update-1.37.3.sql b/db/zm_update-1.37.3.sql new file mode 100644 index 000000000..341c5e162 --- /dev/null +++ b/db/zm_update-1.37.3.sql @@ -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; From 6cd1f6b5f3286af43b1c1b3d09a6e953693c2914 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 13:50:18 -0500 Subject: [PATCH 144/290] Fix memleak on event creation due to not freeing storage object --- src/zm_event.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index d52f606a6..aad16a767 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -103,7 +103,7 @@ 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 == "" ) { @@ -133,22 +133,22 @@ Event::Event( ); id = zmDbDoInsert(sql); - if ( !SetPath(storage) ) { + if (!SetPath(storage)) { // Try another Warning("Failed creating event dir at %s", storage->Path()); sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id()); - if ( monitor->ServerId() ) + if (monitor->ServerId()) sql += stringtf(" AND ServerId=%u", monitor->ServerId()); - Debug(1, "%s", sql.c_str()); + delete storage; storage = nullptr; MYSQL_RES *result = zmDbFetch(sql); - if ( result ) { - for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + if (result) { + for (int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) { storage = new Storage(atoi(dbrow[0])); - if ( SetPath(storage) ) + if (SetPath(storage)) break; delete storage; storage = nullptr; @@ -156,18 +156,18 @@ Event::Event( mysql_free_result(result); result = nullptr; } - if ( !storage ) { + if (!storage) { Info("No valid local storage area found. Trying all other areas."); // Try remote sql = "SELECT `Id` FROM `Storage` WHERE ServerId IS NULL"; - if ( monitor->ServerId() ) + if (monitor->ServerId()) sql += stringtf(" OR ServerId != %u", monitor->ServerId()); result = zmDbFetch(sql); - if ( result ) { + if (result) { for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { storage = new Storage(atoi(dbrow[0])); - if ( SetPath(storage) ) + if (SetPath(storage)) break; delete storage; storage = nullptr; @@ -176,7 +176,7 @@ Event::Event( result = nullptr; } } - if ( !storage ) { + if (!storage) { storage = new Storage(); Warning("Failed to find a storage area to save events."); } @@ -218,6 +218,7 @@ Event::Event( Debug(1, "Video file is %s", video_file.c_str()); } } // end if GetOptVideoWriter + delete storage; } Event::~Event() { From 883772295d263b41044c41fe39020937f9212759 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 13:51:17 -0500 Subject: [PATCH 145/290] spacing and log the new log level string as well as number --- src/zm_logger.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 5c7c5e9a7..f43ea6f30 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -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; From a0215067e4ecaf0ccf3d7f7a370f0bb7ec4db01d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 13:58:52 -0500 Subject: [PATCH 146/290] In multi-server when viewing an event it may be coming from a different server than the serverhost. Use monitorUrl instead of thisUrl in ajax calls and include auth data. Fixes failed ajax when viewing h264 using zms on a multi-server environment --- web/skins/classic/views/js/event.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 050a78d59..1c4f72404 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -34,7 +34,7 @@ function streamReq(data) { data.view = 'request'; data.request = 'stream'; - $j.getJSON(thisUrl, data) + $j.getJSON(monitorUrl, data) .done(getCmdResponse) .fail(logAjaxFail); } @@ -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}; From 036d47a832383353b37af3d148dd86ff13a5e99c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Nov 2021 14:42:08 -0500 Subject: [PATCH 147/290] proper fix to memleak --- src/zm_event.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index aad16a767..9f1124e7b 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -141,7 +141,6 @@ Event::Event( if (monitor->ServerId()) sql += stringtf(" AND ServerId=%u", monitor->ServerId()); - delete storage; storage = nullptr; MYSQL_RES *result = zmDbFetch(sql); @@ -218,7 +217,8 @@ Event::Event( Debug(1, "Video file is %s", video_file.c_str()); } } // end if GetOptVideoWriter - delete storage; + if (storage != monitor->getStorage()) + delete storage; } Event::~Event() { From 193f349e385f9f41a820c54df993305bc1c5ca75 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 12 Nov 2021 13:36:10 -0500 Subject: [PATCH 148/290] implement Event::canEdit --- web/includes/Event.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/web/includes/Event.php b/web/includes/Event.php index 328b06f66..e042849e9 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -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 ?> From 1561adbef930fc61dbb6885ac42eca7117808872 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 12 Nov 2021 15:11:41 -0500 Subject: [PATCH 149/290] Add title to Download button --- web/skins/classic/views/event.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 81d4e97be..e352f305b 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -150,6 +150,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) ) DefaultVideo() ? '' : 'style="display:none;"' ?> > From 8868a0fc41735174b00380c338109ea5d11e1d69 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Oct 2021 14:34:17 -0400 Subject: [PATCH 150/290] enforce default action --- utils/do_debian_package.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index 2a4dd6989..6c8c06c00 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -230,12 +230,11 @@ rm .gitignore cd ../ -if [ !-e "$DIRECTORY.orig.tar.gz" ]; then -read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]" - if [[ $REPLY == [yY] ]]; then - - tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig -fi; +if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then + read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]" + if [[ "$REPLY" == "" || "$REPLY" == [yY] ]]; then + tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig + fi; fi; IFS=',' ;for DISTRO in `echo "$DISTROS"`; do From caeaf91cad332d37d641e05e86a9ce6ef6462e50 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 6 Nov 2021 09:58:31 -0400 Subject: [PATCH 151/290] Only list available ids if there are some --- web/skins/classic/views/monitor.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index f47e29912..7d599904a 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -461,9 +461,12 @@ switch ( $name ) {
-10 Available Ids: - - + + Date: Sun, 7 Nov 2021 11:28:34 -0500 Subject: [PATCH 152/290] Pretty up the v4l field names --- web/ajax/modals/settings.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/web/ajax/modals/settings.php b/web/ajax/modals/settings.php index de42d6c87..e0bdf679c 100644 --- a/web/ajax/modals/settings.php +++ b/web/ajax/modals/settings.php @@ -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 ' - '.translate($setting_uc).' + '.$label.' '.$min.''.$max.' '; @@ -94,7 +99,7 @@ foreach ($ctls as $line) { if ($type == '(bool)') { echo ' - '.translate($setting_uc).' + '.$label.' '.html_radio('new'.$setting_uc, array('0'=>translate('True'), '1', translate('False')), $value, array('disabled'=>'disabled')).' @@ -102,14 +107,14 @@ foreach ($ctls as $line) { } else if ($type == '(int)') { echo ' - '.translate($setting_uc).' + '.$label.' '; } else { echo ' - '.translate($setting_uc).' + '.$label.' '.$value.' '; From 01eac4a277f650057bcb0f54f46abc1c60738e8c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 09:48:57 -0500 Subject: [PATCH 153/290] Default to now instead of ... epoch? when endtime is null. Fixes video playing when event is incomplete --- src/zm_eventstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 5e1ad605d..af9dd8639 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -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(event_data->end_time - event_data->start_time); event_data->frames_duration = std::chrono::duration_cast(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0)); From 9036728bdc9b7ca8dddaa0638d2402f487034d5c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:48:50 -0500 Subject: [PATCH 154/290] Report error if sql fails. Add check for access to specific event. --- web/ajax/events.php | 63 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 4e364242a..090fe476e 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -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; From 944c04e5b46cfa2c7bf883f69df025b78c17f0d0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:49:01 -0500 Subject: [PATCH 155/290] Whitespace --- web/includes/database.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/includes/database.php b/web/includes/database.php index 34ea384fa..01926a26e 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -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; } From 71931f007a9a90f3ca66c9550939c0b8c691c656 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 10:50:39 -0500 Subject: [PATCH 156/290] alert error message is an error is returned instead of rows --- web/skins/classic/views/js/events.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 9f6d34f75..6139ba3e4 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -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}); From 0573c09b5097ce18816b182eefd8bed9e1cf1923 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:51:32 -0500 Subject: [PATCH 157/290] Cleanup and spacing. Rework last_motion_score to be a bit more efficient and use fewer lines. Fix case where MOCORD was not ending/starting event on alarm. --- src/zm_monitor.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 679ea27b7..cdf544682 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1862,8 +1862,6 @@ bool Monitor::Analyse() { Debug(3, "signal and active and modect"); Event::StringSet zoneSet; - int motion_score = last_motion_score; - if (analysis_fps_limit) { double capture_fps = get_capture_fps(); motion_frame_skip = capture_fps / analysis_fps_limit; @@ -1880,7 +1878,7 @@ bool Monitor::Analyse() { } else { Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image); // Get new score. - motion_score = DetectMotion(*(snap->image), zoneSet); + int motion_score = DetectMotion(*(snap->image), zoneSet); snap->zone_stats.reserve(zones.size()); for (const Zone &zone : zones) { @@ -1892,21 +1890,20 @@ bool Monitor::Analyse() { Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)", score, last_motion_score, motion_score); motion_frame_count += 1; - // Why are we updating the last_motion_score too? last_motion_score = motion_score; + if (motion_score) { + if (cause.length()) cause += ", "; + cause += MOTION_CAUSE; + noteSetMap[MOTION_CAUSE] = zoneSet; + } // end if motion_score } } else { Debug(1, "no image so skipping motion detection"); } // end if has image } else { - Debug(1, "Skipped motion detection last motion score was %d", motion_score); + Debug(1, "Skipped motion detection last motion score was %d", last_motion_score); } - if (motion_score) { - score += motion_score; - if (cause.length()) cause += ", "; - cause += MOTION_CAUSE; - noteSetMap[MOTION_CAUSE] = zoneSet; - } // end if motion_score + score += last_motion_score; } else { Debug(1, "Not Active(%d) enabled %d active %d doing motion detection: %d", Active(), enabled, shared_data->active, @@ -2007,7 +2004,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function == MODECT or function == NODECT)) { + if (score and (function == MODECT or function == NODECT or function == MOCORD)) { if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) { // If we should end then previous continuous event and start a new non-continuous event if (event && event->Frames() @@ -2142,7 +2139,8 @@ bool Monitor::Analyse() { shared_data->state = state = ((function != MOCORD) ? IDLE : TAPE); } else { Debug(1, - "State %s because image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + "State %d %s because analysis_image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + state, State_Strings[state].c_str(), analysis_image_count, last_alarm_count, @@ -2161,12 +2159,10 @@ bool Monitor::Analyse() { // Generate analysis images if necessary if ((savejpegs > 1) and snap->image) { for (const Zone &zone : zones) { - if (zone.Alarmed()) { - if (zone.AlarmImage()) { + if (zone.Alarmed() and zone.AlarmImage()) { if (!snap->analysis_image) snap->analysis_image = new Image(*(snap->image)); snap->analysis_image->Overlay(*(zone.AlarmImage())); - } } // end if zone is alarmed } // end foreach zone } // end if savejpegs From bdf55f105e0dc1a18d0de38ba742ec4ff816447b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:54:33 -0500 Subject: [PATCH 158/290] Spacing --- src/zm_event.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 442033c50..d52f606a6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -323,32 +323,32 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) { bool update = false; //Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() ); - if ( newNoteSetMap.size() > 0 ) { - if ( noteSetMap.size() == 0 ) { + if (newNoteSetMap.size() > 0) { + if (noteSetMap.size() == 0) { noteSetMap = newNoteSetMap; update = true; } else { - for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); + for (StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); - ++newNoteSetMapIter ) { + ++newNoteSetMapIter) { const std::string &newNoteGroup = newNoteSetMapIter->first; const StringSet &newNoteSet = newNoteSetMapIter->second; //Info( "Got %d new strings", newNoteSet.size() ); - if ( newNoteSet.size() > 0 ) { + if (newNoteSet.size() > 0) { StringSetMap::iterator noteSetMapIter = noteSetMap.find(newNoteGroup); - if ( noteSetMapIter == noteSetMap.end() ) { - //Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() ); + if (noteSetMapIter == noteSetMap.end()) { + //Debug(3, "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size()); noteSetMap.insert(StringSetMap::value_type(newNoteGroup, newNoteSet)); update = true; } else { StringSet ¬eSet = noteSetMapIter->second; - //Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() ); - for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); + //Debug(3, "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size()); + for (StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); - ++newNoteSetIter ) { + ++newNoteSetIter) { const std::string &newNote = *newNoteSetIter; StringSet::iterator noteSetIter = noteSet.find(newNote); - if ( noteSetIter == noteSet.end() ) { + if (noteSetIter == noteSet.end()) { noteSet.insert(newNote); update = true; } From 82a26a1f83bd8c55b05e9fcf039d6d71e07f5299 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 13:59:05 -0500 Subject: [PATCH 159/290] use != Monitor instead of all the other cases --- src/zm_monitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index cdf544682..81eacc956 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2004,7 +2004,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function == MODECT or function == NODECT or function == MOCORD)) { + 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() From 53c57478b812f555289c20065ac4c2b19a1c597c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 14:00:04 -0500 Subject: [PATCH 160/290] Ignore versioned bootstrap --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 4682851df..91b0fd196 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,7 @@ web/api/lib web/includes/csrf/ web/js/videojs.zoomrotate.js -web/skins/classic/js/bootstrap.js +web/skins/classic/js/bootstrap-4.5.0.js web/skins/classic/js/chosen web/skins/classic/js/dateTimePicker web/skins/classic/js/jquery-*.js From c76e688f05a8c67914c18b44766dc6fd799437b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 15:49:25 -0500 Subject: [PATCH 161/290] Don't exit(0) on QUIT. Instead set zm_terminate=true so that all the cleanup routines run. --- src/zm_monitorstream.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 5c32b8e05..9bc04a311 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -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) { From acff4fb9c0900fce29c14487a25384bec3e84b90 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 14:32:06 -0500 Subject: [PATCH 162/290] rough in fullscreen mode in watch view --- web/skins/classic/js/skin.js | 26 ++++++++++++++++++++++++++ web/skins/classic/views/js/watch.js | 5 +++++ web/skins/classic/views/watch.php | 3 +++ 3 files changed, 34 insertions(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index c7e2afedf..6ede08479 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -947,3 +947,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(); + } +} diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index aacad5126..5ba4b407c 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -970,5 +970,10 @@ function initPage() { }); } // initPage +function watchFullscreen() { + const content = document.getElementById('content'); + openFullscreen(content); +} + // Kick everything off $j(document).ready(initPage); diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index e1e54c3c7..beab28ac1 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -142,6 +142,9 @@ if ( $streamMode == 'jpeg' ) { + From dc9f7b4d1d5960282f46c39c445b3a675753e240 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 16:12:39 -0500 Subject: [PATCH 163/290] Rough in fullscreen mode on montage --- web/skins/classic/views/js/montage.js | 5 +++++ web/skins/classic/views/montage.php | 3 +++ 2 files changed, 8 insertions(+) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 5312928a6..75b3a74d2 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -317,5 +317,10 @@ function initPage() { } selectLayout('#zmMontageLayout'); } + +function watchFullscreen() { + const content = document.getElementById('content'); + openFullscreen(content); +} // Kick everything off $j(document).ready(initPage); diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index 3256cfcc8..b0b10f190 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -206,6 +206,9 @@ if ( canView('System') ) {   + From 9d37fbcd8e7e66e76396200df8e757548aeed668 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Nov 2021 17:01:04 -0500 Subject: [PATCH 164/290] Fix some build warnings on arm --- src/zm_fifo.cpp | 4 ++-- src/zm_monitor.cpp | 22 +++++++++++----------- src/zm_packetqueue.cpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index 319c35c31..a999adc23 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -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 { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 81eacc956..b6e69a19f 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -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(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(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(mem_size), strerror(errno)); disconnect(); return false; } @@ -947,7 +947,7 @@ bool Monitor::connect() { map_fd = -1; return false; } else { - Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, mem_size); + Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, static_cast(mem_size)); close(map_fd); map_fd = -1; return false; @@ -959,18 +959,18 @@ bool Monitor::connect() { mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0); if (mem_ptr == MAP_FAILED) { if (errno == EAGAIN) { - Debug(1, "Unable to map file %s (%jd bytes) to locked memory, trying unlocked", mem_file.c_str(), mem_size); + Debug(1, "Unable to map file %s (%jd bytes) to locked memory, trying unlocked", mem_file.c_str(), static_cast(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(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(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(mem_size), strerror(errno), errno); close(map_fd); map_fd = -1; mem_ptr = nullptr; @@ -2310,7 +2310,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; @@ -2741,7 +2741,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) ) { @@ -2757,7 +2757,7 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const { typedef std::chrono::duration Centiseconds; Centiseconds centi_sec = std::chrono::duration_cast( ts_time.time_since_epoch() - std::chrono::duration_cast(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(centi_sec.count())); found_macro = true; break; } diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index ceef421db..509a25ee6 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -209,7 +209,7 @@ void PacketQueue::clearPackets(const std::shared_ptr &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 From 98e29e7ef6d68b01ac2ac81ab04fd6869dcb39d6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:18:58 -0500 Subject: [PATCH 165/290] implement UrlToZMS in Monitor --- web/includes/Monitor.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index bd9987b2c..6423af11f 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -499,6 +499,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 From 8d0463bbff5e9cef3d954f30e40fab752d8a7020 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:20:19 -0500 Subject: [PATCH 166/290] Implement getElement, setScale in MonitorStream.js --- web/js/MonitorStream.js | 75 ++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index a10d90008..feb4b3611 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -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; } From 6f3e22f2a0ed27140512d13d785bf7401d6729df Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:21:12 -0500 Subject: [PATCH 167/290] If no bottom element is specified, take the last child of content in scaleToFit --- web/skins/classic/js/skin.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 6ede08479..a12005e76 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -584,10 +584,21 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { $j(window).on('resize', endOfResize); //set delayed scaling when Scale to Fit is selected var ratio = baseWidth / baseHeight; var container = $j('#content'); + if (!container) { + console.error("No container found"); + return; + } + + if (!bottomEl || !bottomEl.length) { + bottomEl = $j(container[0].lastElementChild); + } + //console.log(bottomEl); var viewPort = $j(window); - // jquery does not provide a bottom offet, and offset dows not include margins. outerHeight true minus false gives total vertical margins. + // jquery does not provide a bottom offset, and offset does not include margins. outerHeight true minus false gives total vertical margins. var bottomLoc = bottomEl.offset().top + (bottomEl.outerHeight(true) - bottomEl.outerHeight()) + bottomEl.outerHeight(true); + //console.log("bottomLoc: " + bottomEl.offset().top + " + (" + bottomEl.outerHeight(true) + ' - ' + bottomEl.outerHeight() +') + '+bottomEl.outerHeight(true)); var newHeight = viewPort.height() - (bottomLoc - scaleEl.outerHeight(true)); + //console.log("newHeight = " + viewPort.height() +" - " + bottomLoc + ' - ' + scaleEl.outerHeight(true)); var newWidth = ratio * newHeight; if (newWidth > container.innerWidth()) { newWidth = container.innerWidth(); @@ -598,13 +609,15 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { return parseInt($j(this).val()); }).get(); scales.shift(); - var closest; + var closest = null; $j(scales).each(function() { //Set zms scale to nearest regular scale. Zoom does not like arbitrary scale values. if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) { closest = this.valueOf(); } }); - autoScale = closest; + if (closest) { + autoScale = closest; + } return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale}; } From a7fd65d844134b2be36dfa303b606763c6b54800 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:21:38 -0500 Subject: [PATCH 168/290] Put SCALE_BASE in skin.js.php as it is used in many places. --- web/skins/classic/js/skin.js.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/js/skin.js.php b/web/skins/classic/js/skin.js.php index 802a21095..87e08310e 100644 --- a/web/skins/classic/js/skin.js.php +++ b/web/skins/classic/js/skin.js.php @@ -54,6 +54,7 @@ foreach ( $perms as $perm ) { ?> var ANIMATE_THUMBS = ; +var SCALE_BASE = ; var refreshParent = Date: Wed, 10 Nov 2021 14:22:05 -0500 Subject: [PATCH 169/290] Implement Exit Fullscreen using same button --- web/skins/classic/views/js/watch.js | 14 ++++++++++++-- web/skins/classic/views/js/watch.js.php | 6 +++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 5ba4b407c..324e7f7e0 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -971,8 +971,18 @@ function initPage() { } // initPage function watchFullscreen() { - const content = document.getElementById('content'); - openFullscreen(content); + 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 diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index 258a1da73..5b4568dfc 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -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[] = ''; +var translate = { + "Fullscreen": "", + "Exit Fullscreen": "", +}; From 529e889d9912ca015277931e7988f32c39599061 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:23:36 -0500 Subject: [PATCH 170/290] remove extra , --- web/ajax/event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 906fe255a..a0b9cb57a 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -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 { From ac03a88550357aa3ed56f2fa68bdda93f93ad2d7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:12 -0500 Subject: [PATCH 171/290] Include url_to_zms in monitorData --- web/skins/classic/views/js/zone.js.php | 1 + web/skins/classic/views/js/zones.js.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/zone.js.php b/web/skins/classic/views/js/zone.js.php index fc6616327..37eb6db82 100644 --- a/web/skins/classic/views/js/zone.js.php +++ b/web/skins/classic/views/js/zone.js.php @@ -66,6 +66,7 @@ monitorData[monitorData.length] = { 'width': ViewWidth() ?>, 'height':ViewHeight() ?>, 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'url_to_zms': 'UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', 'type': 'Type() ?>', 'refresh': 'Refresh() ?>' }; diff --git a/web/skins/classic/views/js/zones.js.php b/web/skins/classic/views/js/zones.js.php index 180a19d81..338095552 100644 --- a/web/skins/classic/views/js/zones.js.php +++ b/web/skins/classic/views/js/zones.js.php @@ -9,6 +9,7 @@ monitorData[monitorData.length] = { 'width': ViewWidth() ?>, 'height':ViewHeight() ?>, 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'url_to_zms': 'UrlToZMS( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', 'type': 'Type() ?>', 'refresh': 'Refresh() ?>' }; @@ -24,7 +25,7 @@ var STATE_TAPE = ; var stateStrings = new Array(); stateStrings[STATE_IDLE] = ""; -stateStrings[STATE_PREALARM] = ""; +stateStrings[STATE_PREALARM] = ""; stateStrings[STATE_ALARM] = ""; stateStrings[STATE_ALERT] = ""; stateStrings[STATE_TAPE] = ""; From 795c5bb7d728dbe0f7ae68d346dd0f67827009ce Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:29 -0500 Subject: [PATCH 172/290] setScale to auto --- web/skins/classic/views/js/zone.js | 1 + web/skins/classic/views/js/zones.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index 6282cbf8a..58c286b43 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -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); } diff --git a/web/skins/classic/views/js/zones.js b/web/skins/classic/views/js/zones.js index 0ad91942d..67dcb094a 100644 --- a/web/skins/classic/views/js/zones.js +++ b/web/skins/classic/views/js/zones.js @@ -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); From 8872b8be6325a0f90ec5de3c93770fb93f37ac39 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 14:25:45 -0500 Subject: [PATCH 173/290] spacing --- web/skins/classic/views/zones.php | 67 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/web/skins/classic/views/zones.php b/web/skins/classic/views/zones.php index f457ad2fc..423326a98 100644 --- a/web/skins/classic/views/zones.php +++ b/web/skins/classic/views/zones.php @@ -80,15 +80,14 @@ xhtmlHeaders(__FILE__, translate('Zones')); Sorry, your browser does not support inline SVG @@ -96,37 +95,37 @@ xhtmlHeaders(__FILE__, translate('Zones'));  -  fps -
- - - - - - - - - - - - - - - - - - - -
 / ViewWidth()*$monitor->ViewHeight()) ) ?> disabled="disabled"/>
-
- - -
-
-
+
+ + + + + + + + + + + + + + + + + + + +
 / ViewWidth()*$monitor->ViewHeight()) ) ?> disabled="disabled"/>
+
+ + +
+
+
Date: Wed, 10 Nov 2021 16:53:07 -0500 Subject: [PATCH 174/290] Use event->StartTime instead of GetVideoWriterStartTime. Add some parenthesis to make logic clearer and add more info to debug statements --- src/zm_monitor.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index b6e69a19f..d808ddba0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1916,7 +1916,7 @@ bool Monitor::Analyse() { if (event) { Debug(2, "Have event %" PRIu64 " in record", event->Id()); - if (section_length != Seconds(0) && (timestamp - GetVideoWriterStartTime() >= section_length) + if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length) && ((function == MOCORD && event_close_mode != CLOSE_TIME) || (function == RECORD && event_close_mode == CLOSE_TIME) || std::chrono::duration_cast(timestamp.time_since_epoch()) % section_length == Seconds(0))) { @@ -1925,8 +1925,8 @@ bool Monitor::Analyse() { image_count, event->Id(), static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), - static_cast(std::chrono::duration_cast(GetVideoWriterStartTime().time_since_epoch()).count()), - static_cast(std::chrono::duration_cast(timestamp - GetVideoWriterStartTime()).count()), + static_cast(std::chrono::duration_cast(event->StartTime().time_since_epoch()).count()), + static_cast(std::chrono::duration_cast(timestamp - event->StartTime()).count()), static_cast(Seconds(section_length).count())); closeEvent(); } // end if section_length @@ -2009,21 +2009,22 @@ bool Monitor::Analyse() { // 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(std::chrono::duration_cast(timestamp - GetVideoWriterStartTime()).count()), - static_cast(Seconds(min_section_length).count())); + static_cast(std::chrono::duration_cast(timestamp - event->StartTime()).count()), + static_cast(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 @@ -2120,8 +2121,10 @@ bool Monitor::Analyse() { Info("%s: %03d - Gone into alert state", name.c_str(), analysis_image_count); shared_data->state = state = ALERT; } else if (state == ALERT) { - if (analysis_image_count - last_alarm_count > post_event_count - && timestamp - GetVideoWriterStartTime() >= min_section_length) { + if ( + ((analysis_image_count - last_alarm_count) > post_event_count) + && + ((timestamp - event->StartTime()) >= min_section_length)) { Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name.c_str(), analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames()); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) @@ -2168,7 +2171,6 @@ bool Monitor::Analyse() { } // 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) { @@ -2183,7 +2185,7 @@ bool Monitor::Analyse() { if (event) { if (noteSetMap.size() > 0) event->updateNotes(noteSetMap); - if (section_length != Seconds(0) && (timestamp - GetVideoWriterStartTime() >= section_length)) { + if (section_length != Seconds(0) && (timestamp - event->StartTime() >= section_length)) { Warning("%s: %03d - event %" PRIu64 ", has exceeded desired section length. %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64, name.c_str(), analysis_image_count, event->Id(), static_cast(std::chrono::duration_cast(timestamp.time_since_epoch()).count()), From e35dc3902ef5f10268603412f190fe3adeb6172c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 16:53:29 -0500 Subject: [PATCH 175/290] Make state enum start at 0 as we are indexing into an array for StateStrings --- src/zm_monitor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 56785405f..5b9a2ce46 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -100,7 +100,7 @@ public: } Deinterlace; typedef enum { - UNKNOWN=-1, + UNKNOWN, IDLE, PREALARM, ALARM, From c84f42e2804519bc6e11a1bb58b579af9bc97f65 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Nov 2021 17:05:46 -0500 Subject: [PATCH 176/290] Set to never timeout while generating video --- web/skins/classic/views/js/video.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/skins/classic/views/js/video.js b/web/skins/classic/views/js/video.js index 970119f4f..c764f33b5 100644 --- a/web/skins/classic/views/js/video.js +++ b/web/skins/classic/views/js/video.js @@ -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) From d00430f799c450f7f213e9aff364b26c6a7ac6bb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 15 Nov 2021 09:47:11 -0500 Subject: [PATCH 177/290] Add ModelId to MonitorPresets --- db/zm_create.sql.in | 1 + db/zm_update-1.37.3.sql | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index ecc2d477d..9a048886d 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -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, diff --git a/db/zm_update-1.37.3.sql b/db/zm_update-1.37.3.sql index 341c5e162..9002ce8e2 100644 --- a/db/zm_update-1.37.3.sql +++ b/db/zm_update-1.37.3.sql @@ -45,3 +45,26 @@ SET @s = (SELECT IF( 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; From e63222d7337edfa8643e0e9064bbf83253e30266 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 15 Nov 2021 16:30:03 -0500 Subject: [PATCH 178/290] Add IGNORE so it does UPSERT --- db/manufacturers.sql | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/db/manufacturers.sql b/db/manufacturers.sql index be15f9c01..3761f5cbe 100644 --- a/db/manufacturers.sql +++ b/db/manufacturers.sql @@ -1,24 +1,24 @@ -INSERT INTO Manufacturers VALUES (1, 'Acti'); -INSERT INTO Manufacturers VALUES (2, 'Amcrest'); -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 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'); +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'); From 4e9a56624d8d7f86f3ad83059044f77599af42a1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 15 Nov 2021 16:30:17 -0500 Subject: [PATCH 179/290] Use UPSERTS and add some more models --- db/models.sql | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/db/models.sql b/db/models.sql index b7150d816..ffafb76a8 100644 --- a/db/models.sql +++ b/db/models.sql @@ -1,30 +1,41 @@ /* INSERT INTO Manufacturers VALUES (1, 'Acti'); */ -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A21'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A23'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A24'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A28'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A31'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A310'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A311'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A32'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A41'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A415'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A416'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A418'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A42'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A421'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A43'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A45'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A46'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A48'); -INSERT INTO Models (ManufacturerId,Name) VALUES (1, 'A74'); +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'); From 6cbc4c0a7af6d1e977997283a4f7e214842966be Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 15 Nov 2021 16:30:39 -0500 Subject: [PATCH 180/290] Update MonirorPresets to link to Amcrest cams --- db/zm_update-1.37.3.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/zm_update-1.37.3.sql b/db/zm_update-1.37.3.sql index 9002ce8e2..5ae4aa1b1 100644 --- a/db/zm_update-1.37.3.sql +++ b/db/zm_update-1.37.3.sql @@ -68,3 +68,6 @@ SET @s = (SELECT IF( PREPARE stmt FROM @s; EXECUTE stmt; + +UPDATE `MonitorPresets` SET `ModelId`=(SELECT `Id` FROM `Models` WHERE `Name`='IP8M-T2499EW') WHERE `Name` like 'Amcrest, IP8M-T2499EW +%'; From f48511acba1dd033feeab533d502dcc4aadbf45f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 16 Nov 2021 09:19:42 -0500 Subject: [PATCH 181/290] Add NULL for ModelId column when adding MonitorPresets. --- db/zm_create.sql.in | 150 ++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 9a048886d..d9d4f96c3 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -974,81 +974,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://:@/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://:@/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','',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','',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','',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','',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','',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','',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','',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','',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','',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','',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','',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,1,4,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,1,4,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,1,4,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,1,4,NULL,':',100,100); -INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, unicast','Remote','rtsp',0,255,'rtsp','rtpUni','',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','',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','',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','',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','',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',':@','80','/video.cgi',NULL,640,480,0,NULL,1,'34',NULL,':@',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','',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','',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','',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','',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','',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','',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','',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,1,5,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,1,5,NULL,':',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, jpeg','Remote','http',0,0,'http','simple','',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','',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','',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','',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','','8080','/video','',1920,1080,0,NULL,0,'0','','',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'VEO Observer, jpeg','Remote','http',0,0,'http','simple','',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','',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','',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:///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://: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:///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@: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','',80,'/cgi-bin/nph-zms?mode=jpeg&monitor=&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://:@:554/11',NULL,704,576,0,NULL,1,'10','','',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI8608W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://:@:554/11',NULL,640,480,0,NULL,1,'11','','',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI9821W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://:@:88/videoMain',NULL,1280,720,0,NULL,1,'12','','',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Loftek Sentinel PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'','80','/videostream.cgi?user=&pwd=&resolution=32&rate=11',NULL,640,480,4,NULL,1,'13','',':@',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'Airlink 777W PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,':@','80','/cgi/mjpg/mjpg.cgi',NULL,640,480,4,NULL,1,'7','',':@',100,100); -INSERT INTO MonitorPresets VALUES (NULL,'SunEyes SP-P1802SWPTZ','Libvlc','/dev/video','0',255,'','rtpMulti','','80','rtsp://:554/11','',1920,1080,0,0.00,1,'16','-speed=64',':',100,33); -INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1280x720, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp:///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:///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://:@/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://:@/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','',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','',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','',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','',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','',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','',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','',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','',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','',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','',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','',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,1,4,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,1,4,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,1,4,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Axis IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,1,4,NULL,':',100,100); +INSERT into MonitorPresets VALUES (NULL,NULL,'Axis IP, mpeg4, unicast','Remote','rtsp',0,255,'rtsp','rtpUni','',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','',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','',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','',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','',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',':@','80','/video.cgi',NULL,640,480,0,NULL,1,'34',NULL,':@',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','',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','',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','',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','',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','',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','',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','',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,1,5,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Panasonic IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,1,5,NULL,':',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Gadspot IP, jpeg','Remote','http',0,0,'http','simple','',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','',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','',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','',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','','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','',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','',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','',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:///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://: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:///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@: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','',80,'/cgi-bin/nph-zms?mode=jpeg&monitor=&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://:@:554/11',NULL,704,576,0,NULL,1,'10','','',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Foscam FI8608W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://:@:554/11',NULL,640,480,0,NULL,1,'11','','',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Foscam FI9821W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://:@:88/videoMain',NULL,1280,720,0,NULL,1,'12','','',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Loftek Sentinel PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'','80','/videostream.cgi?user=&pwd=&resolution=32&rate=11',NULL,640,480,4,NULL,1,'13','',':@',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Airlink 777W PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,':@','80','/cgi/mjpg/mjpg.cgi',NULL,640,480,4,NULL,1,'7','',':@',100,100); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'SunEyes SP-P1802SWPTZ','Libvlc','/dev/video','0',255,'','rtpMulti','','80','rtsp://:554/11','',1920,1080,0,0.00,1,'16','-speed=64',':',100,33); +INSERT INTO MonitorPresets VALUES (NULL,NULL,'Qihan IP, 1280x720, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp:///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:///tcp_live/ch0_0',NULL,1920,1080,3,NULL,0,NULL,NULL,NULL,100,100); -- -- Add some zone preset values From 20629fdf5a77505708842f2f910822799102e641 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 16 Nov 2021 09:20:14 -0500 Subject: [PATCH 182/290] Include Manufacturer and Model in telemetry --- scripts/zmtelemetry.pl.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/zmtelemetry.pl.in b/scripts/zmtelemetry.pl.in index a3debabdb..c164df7e4 100644 --- a/scripts/zmtelemetry.pl.in +++ b/scripts/zmtelemetry.pl.in @@ -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({}); From 78a803abf87bd724dcaa69de4401b561a847b8a5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 16 Nov 2021 09:47:34 -0500 Subject: [PATCH 183/290] Add Model and Manufacturer to telemetry listing --- web/lang/en_gb.php | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 8b412cd39..8c6ce9adb 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -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:
  • A unique identifier (UUID)
  • City based location is gathered by querying ipinfo.io. City, region, country, latitude, and longitude parameters are saved. The latitude and longitude coordinates are accurate down to the city or town level only!
  • Current time
  • Total number of monitors
  • Total number of events
  • System architecture
  • Operating system kernel, distro, and distro version
  • Version of ZoneMinder
  • Total amount of memory
  • Number of cpu cores
', - 'PrivacyMonitorList' => 'The following configuration parameters from each monitor are collected:
  • Id
  • Name
  • Type
  • Function
  • Width
  • Height
  • Colours
  • MaxFPS
  • AlarmMaxFPS
', + 'PrivacyTelemetryList' => 'The ZoneMinder Telemetry daemon collects the following data about your system: +
    +
  • A unique identifier (UUID)
  • +
  • City based location is gathered by querying ipinfo.io. City, region, country, latitude, and longitude parameters are saved. The latitude and longitude coordinates are accurate down to the city or town level only!
  • +
  • Current time
  • +
  • Total number of monitors
  • +
  • Total number of events
  • +
  • System architecture
  • +
  • Operating system kernel, distro, and distro version
  • +
  • Version of ZoneMinder
  • +
  • Total amount of memory
  • +
  • Number of cpu cores
  • +
', + 'PrivacyMonitorList' => 'The following configuration parameters from each monitor are collected: +
    +
  • Id
  • +
  • Name
  • +
  • Manufacturer
  • +
  • Model
  • +
  • Type
  • +
  • Function
  • +
  • Width
  • +
  • Height
  • +
  • Colours
  • +
  • MaxFPS
  • +
  • AlarmMaxFPS
  • +
', 'PrivacyConclusionText' => 'We are NOT collecting any image specific data from your cameras. We don’t 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', From 03897bf68e10a0c2a47172947dbeb45d3bd4cc3d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 16 Nov 2021 09:49:49 -0500 Subject: [PATCH 184/290] Add privacy to options tabs so we can get back to it. --- web/skins/classic/views/options.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 22b164202..25cad40cc 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -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')); - ?> @@ -62,7 +62,7 @@ xhtmlHeaders(__FILE__, translate('Options'));