From 0b5ebbbe59e861a1c1b15c715b2caa503fd3ac3a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Mar 2020 14:56:25 -0400 Subject: [PATCH 01/28] add focal to ubuntu builds --- utils/do_debian_package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index 539205e3b..af9921294 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -80,7 +80,7 @@ fi; if [ "$DISTROS" == "" ]; then if [ "$RELEASE" != "" ]; then - DISTROS="xenial,bionic,disco,eoan,trusty" + DISTROS="xenial,bionic,disco,eoan,focal,trusty" else DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`; fi; From cbda9848ab8154a25c4a5092372d2ef9f203766c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 12:06:07 -0400 Subject: [PATCH 02/28] Fix SLOW FWD not working --- src/zm_eventstream.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index bb61ca357..4e2eeb1b7 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -76,7 +76,7 @@ bool EventStream::loadInitialEventData(int monitor_id, time_t event_time) { curr_frame_id = 1; // curr_frame_id is 1-based if ( event_time >= event_data->start_time ) { Debug(2, "event time is after event start"); - for (unsigned int i = 0; i < event_data->frame_count; i++ ) { + for ( unsigned int i = 0; i < event_data->frame_count; i++ ) { //Info( "eft %d > et %d", event_data->frames[i].timestamp, event_time ); if ( event_data->frames[i].timestamp >= event_time ) { curr_frame_id = i+1; @@ -378,6 +378,8 @@ void EventStream::processCommand(const CmdMsg *msg) { paused = true; replay_rate = ZM_RATE_BASE; step = 1; + if ( (unsigned int)curr_frame_id < event_data->frame_count ) + curr_frame_id += 1; break; case CMD_SLOWREV : Debug(1, "Got SLOW REV command"); @@ -848,20 +850,15 @@ void EventStream::runStream() { // commands may set send_frame to true while ( checkCommandQueue() && !zm_terminate ) { // The idea is to loop here processing all commands before proceeding. - Debug(1, "Have command queue"); } - Debug(2, "Done command queue"); // Update modified time of the socket .lock file so that we can tell which ones are stale. if ( now.tv_sec - last_comm_update.tv_sec > 3600 ) { touch(sock_path_lock); last_comm_update = now; } - } else { - Debug(2, "Not checking command queue"); } - // Get current frame data FrameData *frame_data = &event_data->frames[curr_frame_id-1]; @@ -1017,7 +1014,8 @@ void EventStream::runStream() { curr_frame_id += step; // Detects when we hit end of event and will load the next event or previous event - checkEventLoaded(); + if ( !paused ) + checkEventLoaded(); } // end while ! zm_terminate #if HAVE_LIBAVCODEC if ( type == STREAM_MPEG ) From a5ec89ab1b2408a740a25428682d0aebec0f486a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Mar 2020 15:30:52 -0400 Subject: [PATCH 03/28] use bool instead of my_bool to fix #2886 --- 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 77c149f03..8e6258b0b 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -40,7 +40,7 @@ bool zmDbConnect() { Error("Can't initialise database connection: %s", mysql_error(&dbconn)); return false; } - my_bool reconnect = 1; + bool reconnect = 1; if ( mysql_options(&dbconn, MYSQL_OPT_RECONNECT, &reconnect) ) Error("Can't set database auto reconnect option: %s", mysql_error(&dbconn)); if ( !staticConfig.DB_SSL_CA_CERT.empty() ) From ea7bea4c6e20e4e0cd558c86c4f3006cfede50a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Mar 2020 15:30:16 -0400 Subject: [PATCH 04/28] fix warnings because length() returns long unsigned int, but gnutls_datum_t size is unsigned int. --- src/zm_rtsp_auth.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_rtsp_auth.cpp b/src/zm_rtsp_auth.cpp index 81aa13c27..2f8b2c3ce 100644 --- a/src/zm_rtsp_auth.cpp +++ b/src/zm_rtsp_auth.cpp @@ -144,7 +144,7 @@ std::string Authenticator::computeDigestResponse(std::string &method, std::strin #if HAVE_DECL_MD5 MD5((unsigned char*)ha1Data.c_str(), ha1Data.length(), md5buf); #elif HAVE_DECL_GNUTLS_FINGERPRINT - gnutls_datum_t md5dataha1 = { (unsigned char*)ha1Data.c_str(), ha1Data.length() }; + gnutls_datum_t md5dataha1 = { (unsigned char*)ha1Data.c_str(), (unsigned int)ha1Data.length() }; gnutls_fingerprint( GNUTLS_DIG_MD5, &md5dataha1, md5buf, &md5len ); #endif for ( unsigned int j = 0; j < md5len; j++ ) { @@ -159,7 +159,7 @@ std::string Authenticator::computeDigestResponse(std::string &method, std::strin #if HAVE_DECL_MD5 MD5((unsigned char*)ha2Data.c_str(), ha2Data.length(), md5buf ); #elif HAVE_DECL_GNUTLS_FINGERPRINT - gnutls_datum_t md5dataha2 = { (unsigned char*)ha2Data.c_str(), ha2Data.length() }; + gnutls_datum_t md5dataha2 = { (unsigned char*)ha2Data.c_str(), (unsigned int)ha2Data.length() }; gnutls_fingerprint( GNUTLS_DIG_MD5, &md5dataha2, md5buf, &md5len ); #endif for ( unsigned int j = 0; j < md5len; j++ ) { @@ -180,7 +180,7 @@ std::string Authenticator::computeDigestResponse(std::string &method, std::strin #if HAVE_DECL_MD5 MD5((unsigned char*)digestData.c_str(), digestData.length(), md5buf); #elif HAVE_DECL_GNUTLS_FINGERPRINT - gnutls_datum_t md5datadigest = { (unsigned char*)digestData.c_str(), digestData.length() }; + gnutls_datum_t md5datadigest = { (unsigned char*)digestData.c_str(), (unsigned int)digestData.length() }; gnutls_fingerprint( GNUTLS_DIG_MD5, &md5datadigest, md5buf, &md5len ); #endif for ( unsigned int j = 0; j < md5len; j++ ) { From eed45ae66c449af305c1f24a944535b1c6c8e4fd Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Tue, 24 Mar 2020 09:29:19 -0700 Subject: [PATCH 05/28] Fix 2892 --- CMakeLists.txt | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 018fc0eb0..a15267582 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -738,14 +738,6 @@ if(HAVE_OPENSSL_MD5_H) "unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)" "NULL" "openssl/md5.h" HAVE_MD5_OPENSSL) endif(HAVE_OPENSSL_MD5_H) -if(HAVE_GNUTLS_OPENSSL_H) - set(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}") - set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}") - check_prototype_definition( - MD5 - "unsigned char *MD5 (const unsigned char *buf, unsigned long len, unsigned char *md)" "NULL" "gnutls/openssl.h" - HAVE_MD5_GNUTLS) -endif(HAVE_GNUTLS_OPENSSL_H) if(HAVE_GNUTLS_GNUTLS_H) set(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}") set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}") @@ -754,13 +746,13 @@ if(HAVE_GNUTLS_GNUTLS_H) "int gnutls_fingerprint (gnutls_digest_algorithm_t algo, const gnutls_datum_t * data, void *result, size_t * result_size)" "0" "stdlib.h;gnutls/gnutls.h" HAVE_DECL_GNUTLS_FINGERPRINT) endif(HAVE_GNUTLS_GNUTLS_H) -if(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS) +if(HAVE_MD5_OPENSSL) set(HAVE_DECL_MD5 1) -else(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS) +else(HAVE_MD5_OPENSSL) message(AUTHOR_WARNING "ZoneMinder requires a working MD5 function for hashed authenication but none were found - hashed authenication will not be available") -endif(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS) +endif(HAVE_MD5_OPENSSL) # Dirty fix for zm_user only using openssl's md5 if gnutls and gcrypt are not available. # This needs to be fixed in zm_user.[h,cpp] but such fix will also require changes to configure.ac if(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL) From cf6b24b432c4492b24117042e22e7b8242793b72 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Mon, 16 Mar 2020 14:49:27 -0400 Subject: [PATCH 06/28] add ES status to telemetry and --show option to display what is being sent to ZM --- scripts/zmtelemetry.pl.in | 47 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/scripts/zmtelemetry.pl.in b/scripts/zmtelemetry.pl.in index 9b5e7c89d..82ceeac96 100644 --- a/scripts/zmtelemetry.pl.in +++ b/scripts/zmtelemetry.pl.in @@ -45,6 +45,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my $help = 0; my $force = 0; +my $show = 0; # Interval between version checks my $interval; my $version; @@ -52,6 +53,7 @@ my $version; GetOptions( force => \$force, help => \$help, + show => \$show, interval => \$interval, version => \$version ); @@ -59,6 +61,14 @@ if ( $version ) { print( ZoneMinder::Base::ZM_VERSION . "\n"); exit(0); } +if ($show) { + my %telemetry; + my $dbh = zmDbConnect(); + collectData($dbh, \%telemetry); + my $result = jsonEncode(\%telemetry); + print ($result); + exit(0); +} if ( $help ) { pod2usage(-exitstatus => -1); } @@ -89,21 +99,9 @@ while( 1 ) { my $dbh = zmDbConnect(); # Build the telemetry hash # We should keep *BSD systems in mind when calling system commands + my %telemetry; - $telemetry{uuid} = getUUID($dbh); - @telemetry{qw(city region country latitude longitude)} = getGeo(); - $telemetry{timestamp} = strftime('%Y-%m-%dT%H:%M:%S%z', localtime()); - $telemetry{monitor_count} = countQuery($dbh,'Monitors'); - $telemetry{event_count} = countQuery($dbh,'Events'); - $telemetry{architecture} = runSysCmd('uname -p'); - ($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro(); - $telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION; - $telemetry{system_memory} = totalmem(); - $telemetry{processor_count} = cpu_count(); - $telemetry{monitors} = getMonitorRef($dbh); - - Info('Sending data to ZoneMinder Telemetry server.'); - + collectData($dbh,\%telemetry); my $result = jsonEncode(\%telemetry); if ( sendData($result) ) { @@ -126,6 +124,24 @@ print 'ZoneMinder Telemetry Agent exiting at '.strftime('%y/%m/%d %H:%M:%S', loc # SUBROUTINES # ############### +# collect data to send +sub collectData { + my $dbh = shift; + my $telemetry = shift; + $telemetry->{uuid} = getUUID($dbh); + ($telemetry->{city},$telemetry->{region},$telemetry->{country},$telemetry->{latitude},$telemetry->{longitude})=getGeo(); + $telemetry->{timestamp} = strftime('%Y-%m-%dT%H:%M:%S%z', localtime()); + $telemetry->{monitor_count} = countQuery($dbh,'Monitors'); + $telemetry->{event_count} = countQuery($dbh,'Events'); + $telemetry->{architecture} = runSysCmd('uname -p'); + ($telemetry->{kernel}, $telemetry->{distro}, $telemetry->{version}) = getDistro(); + $telemetry->{zm_version} = ZoneMinder::Base::ZM_VERSION; + $telemetry->{system_memory} = totalmem(); + $telemetry->{processor_count} = cpu_count(); + $telemetry->{use_event_server} = $Config{ZM_OPT_USE_EVENTNOTIFICATION}; + $telemetry->{monitors} = getMonitorRef($dbh); +} + # Find, verify, then run the supplied system command sub runSysCmd { my $msg = shift; @@ -365,7 +381,7 @@ zmtelemetry.pl - Send usage information to the ZoneMinder development team =head1 SYNOPSIS - zmtelemetry.pl [--force] [--help] [--interval=seconds] [--version] + zmtelemetry.pl [--force] [--help] [--show] [--interval=seconds] [--version] =head1 DESCRIPTION @@ -382,6 +398,7 @@ console under Options. --force Force the script to upload it's data instead of waiting for the defined interval since last upload. --help Display usage information + --show Displays telemetry data that is sent to zoneminder --interval Override the default configured interval since last upload. The value should be given in seconds, but can be an expression such as 24*60*60. From 45299955a1b07b0ad5c3bf7fe84db0ac4a8fb761 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 12:06:07 -0400 Subject: [PATCH 07/28] Fix SLOW FWD not working --- src/zm_eventstream.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 034ff778a..ee495a2e0 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -76,7 +76,7 @@ bool EventStream::loadInitialEventData(int monitor_id, time_t event_time) { curr_frame_id = 1; // curr_frame_id is 1-based if ( event_time >= event_data->start_time ) { Debug(2, "event time is after event start"); - for (unsigned int i = 0; i < event_data->frame_count; i++ ) { + for ( unsigned int i = 0; i < event_data->frame_count; i++ ) { //Info( "eft %d > et %d", event_data->frames[i].timestamp, event_time ); if ( event_data->frames[i].timestamp >= event_time ) { curr_frame_id = i+1; @@ -377,6 +377,8 @@ void EventStream::processCommand(const CmdMsg *msg) { paused = true; replay_rate = ZM_RATE_BASE; step = 1; + if ( (unsigned int)curr_frame_id < event_data->frame_count ) + curr_frame_id += 1; break; case CMD_SLOWREV : Debug(1, "Got SLOW REV command"); @@ -845,20 +847,15 @@ void EventStream::runStream() { // commands may set send_frame to true while ( checkCommandQueue() && !zm_terminate ) { // The idea is to loop here processing all commands before proceeding. - Debug(1, "Have command queue"); } - Debug(2, "Done command queue"); // Update modified time of the socket .lock file so that we can tell which ones are stale. if ( now.tv_sec - last_comm_update.tv_sec > 3600 ) { touch(sock_path_lock); last_comm_update = now; } - } else { - Debug(2, "Not checking command queue"); } - // Get current frame data FrameData *frame_data = &event_data->frames[curr_frame_id-1]; @@ -1014,7 +1011,8 @@ void EventStream::runStream() { curr_frame_id += step; // Detects when we hit end of event and will load the next event or previous event - checkEventLoaded(); + if ( !paused ) + checkEventLoaded(); } // end while ! zm_terminate #if HAVE_LIBAVCODEC if ( type == STREAM_MPEG ) From af36cc3e52c100244051b2c4de0503b68887120a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 13:57:00 -0400 Subject: [PATCH 08/28] Fix starting and stopping zmcontrol processes across servers. --- web/includes/Monitor.php | 12 ++++++++---- web/includes/actions/monitor.php | 6 ++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index e2eee7ba9..8c45c0d27 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -497,6 +497,10 @@ class Monitor extends ZM_Object { if ( !count($options) ) { if ( $command == 'quit' ) { $options['command'] = 'quit'; + } else if ( $command == 'start' ) { + $options['command'] = 'start'; + } else if ( $command == 'stop' ) { + $options['command'] = 'stop'; } else { Warning("No commands to send to zmcontrol from $command"); return false; @@ -531,7 +535,7 @@ class Monitor extends ZM_Object { } else if ( $this->ServerId() ) { $Server = $this->Server(); - $url = ZM_BASE_PROTOCOL . '://'.$Server->Hostname().'/zm/api/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zmcontrol.json'; + $url = ZM_BASE_PROTOCOL . '://'.$Server->Hostname().'/zm/api/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json'; if ( ZM_OPT_USE_AUTH ) { if ( ZM_AUTH_RELAY == 'hashed' ) { $url .= '?auth='.generateAuthHash( ZM_AUTH_HASH_IPS ); @@ -547,12 +551,12 @@ class Monitor extends ZM_Object { $context = stream_context_create(); try { $result = file_get_contents($url, false, $context); - if ($result === FALSE) { /* Handle error */ - Error("Error restarting zma using $url"); + if ( $result === FALSE ) { /* Handle error */ + Error("Error sending command using $url"); return false; } } catch ( Exception $e ) { - Error("Except $e thrown trying to restart zma"); + Error("Exception $e thrown trying to send command to $url"); return false; } } else { diff --git a/web/includes/actions/monitor.php b/web/includes/actions/monitor.php index 94e527e29..78b64e13c 100644 --- a/web/includes/actions/monitor.php +++ b/web/includes/actions/monitor.php @@ -92,6 +92,9 @@ if ( $action == 'monitor' ) { if ( $monitor->Type() != 'WebSite' ) { $monitor->zmaControl('stop'); $monitor->zmcControl('stop'); + if ( $monitor->Controllable() ) { + $monitor->sendControlCommand('stop'); + } } # These are used in updating zones @@ -264,8 +267,7 @@ if ( $action == 'monitor' ) { $monitor->zmaControl('start'); if ( $monitor->Controllable() ) { - require_once('includes/control_functions.php'); - $monitor->sendControlCommand('quit'); + $monitor->sendControlCommand('start'); } } // really should thump zmwatch and maybe zmtrigger too. From b354641df3dd4538724b87ddf18809ba183fb711 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 13:57:19 -0400 Subject: [PATCH 09/28] fix syntax errors in triggers in monitor view --- web/skins/classic/views/monitor.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 76614decb..a78c6f615 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -729,12 +729,12 @@ switch ( $tab ) { continue; if ( $optCount && ($optCount%$breakCount == 0) ) echo '
'; - echo 'Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"':''). '/> '. $optTrigger; - $optCount ++; + echo 'Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"' : ''). '/> '. $optTrigger; + $optCount ++; } # end foreach trigger option if ( !$optCount ) { - echo ''. translate('NoneAvailable') .''; + echo ''.translate('NoneAvailable').''; } ?> From 3e55795cad2e5dc1de6a9f8e108ef6b761c75d8b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 13:57:43 -0400 Subject: [PATCH 10/28] Handle different command line syntax for zmcontrol.pl --- web/api/app/Controller/MonitorsController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index 92114a558..3818f69d3 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -379,6 +379,8 @@ class MonitorsController extends AppController { $args = ''; if ( $daemon == 'zmc' and $monitor['Type'] == 'Local' ) { $args = '-d ' . $monitor['Device']; + } else if ( $daemon == 'zmcontrol.pl' ) { + $args = '--id '.$id; } else { $args = '-m ' . $id; } From e98f4227306773c10ed2a48200703e59a8c8133e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 15:04:28 -0400 Subject: [PATCH 11/28] Use %d for values that are actually integer in debug statements --- src/zm_local_camera.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index c6030f08a..f06f9f958 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -55,7 +55,7 @@ static _AVPIXELFORMAT getFfPixFormatFromV4lPalette(int v4l_version, int palette) #if ZM_HAS_V4L2 if ( v4l_version == 2 ) { - switch( palette ) { + switch ( palette ) { #if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444) case V4L2_PIX_FMT_RGB444 : pixFormat = AV_PIX_FMT_RGB444; @@ -745,12 +745,12 @@ void LocalCamera::Initialise() { Debug(4, " v4l2_data.fmt.type = %08x\n" - " v4l2_data.fmt.fmt.pix.width = %08x\n" - " v4l2_data.fmt.fmt.pix.height = %08x\n" + " v4l2_data.fmt.fmt.pix.width = %d\n" + " v4l2_data.fmt.fmt.pix.height = %d\n" " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" " v4l2_data.fmt.fmt.pix.field = %08x\n" - " v4l2_data.fmt.fmt.pix.bytesperline = %08x\n" - " v4l2_data.fmt.fmt.pix.sizeimage = %08x\n" + " v4l2_data.fmt.fmt.pix.bytesperline = %d\n" + " v4l2_data.fmt.fmt.pix.sizeimage = %d\n" " v4l2_data.fmt.fmt.pix.colorspace = %08x\n" " v4l2_data.fmt.fmt.pix.priv = %08x\n" , v4l2_data.fmt.type @@ -788,12 +788,12 @@ void LocalCamera::Initialise() { /* Note VIDIOC_S_FMT may change width and height. */ Debug(4, " v4l2_data.fmt.type = %08x\n" - " v4l2_data.fmt.fmt.pix.width = %08x\n" - " v4l2_data.fmt.fmt.pix.height = %08x\n" + " v4l2_data.fmt.fmt.pix.width = %d\n" + " v4l2_data.fmt.fmt.pix.height = %d\n" " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" " v4l2_data.fmt.fmt.pix.field = %08x\n" - " v4l2_data.fmt.fmt.pix.bytesperline = %08x\n" - " v4l2_data.fmt.fmt.pix.sizeimage = %08x\n" + " v4l2_data.fmt.fmt.pix.bytesperline = %d\n" + " v4l2_data.fmt.fmt.pix.sizeimage = %d\n" " v4l2_data.fmt.fmt.pix.colorspace = %08x\n" " v4l2_data.fmt.fmt.pix.priv = %08x\n" , v4l2_data.fmt.type From 79ad2ec87d63e806913cb80d695869dfdebea8d3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 15:08:32 -0400 Subject: [PATCH 12/28] better debug logging for SLOWFWD and SLOWREV listing new frame_id --- src/zm_eventstream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 4e2eeb1b7..8739dfd54 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -374,20 +374,20 @@ void EventStream::processCommand(const CmdMsg *msg) { } break; case CMD_SLOWFWD : - Debug(1, "Got SLOW FWD command"); paused = true; replay_rate = ZM_RATE_BASE; step = 1; if ( (unsigned int)curr_frame_id < event_data->frame_count ) curr_frame_id += 1; + Debug(1, "Got SLOWFWD command new frame id %d", curr_frame_id); break; case CMD_SLOWREV : - Debug(1, "Got SLOW REV command"); paused = true; replay_rate = ZM_RATE_BASE; step = -1; curr_frame_id -= 1; if ( curr_frame_id < 1 ) curr_frame_id = 1; + Debug(1, "Got SLOWREV command new frame id %d", curr_frame_id); break; case CMD_FASTREV : Debug(1, "Got FAST REV command"); From bc950c9a34f414e6dabc88893a749b0f5968e171 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 15:11:39 -0400 Subject: [PATCH 13/28] Remove and as they are not used --- src/zm_eventstream.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index d0b5827e7..62be73015 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -20,9 +20,6 @@ #ifndef ZM_EVENTSTREAM_H #define ZM_EVENTSTREAM_H -#include -#include - #include "zm_image.h" #include "zm_stream.h" #include "zm_video.h" @@ -97,7 +94,7 @@ class EventStream : public StreamBase { public: EventStream() { mode = DEFAULT_MODE; - replay_rate = DEFAULT_RATE; + replay_rate = DEFAULT_RATE; forceEventChange = false; @@ -121,8 +118,8 @@ class EventStream : public StreamBase { void runStream(); Image *getImage(); private: - AVCodecContext *input_codec_context; - AVCodec *input_codec; + AVCodecContext *input_codec_context; + AVCodec *input_codec; }; #endif // ZM_EVENTSTREAM_H From c880793fdc411558236e8d8c55ec29c455e6c416 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2020 15:34:36 -0400 Subject: [PATCH 14/28] bump version to 1.34.7 --- db/zm_update-1.34.7.sql | 5 +++++ distros/redhat/zoneminder.spec | 2 +- version | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 db/zm_update-1.34.7.sql diff --git a/db/zm_update-1.34.7.sql b/db/zm_update-1.34.7.sql new file mode 100644 index 000000000..ba86b1202 --- /dev/null +++ b/db/zm_update-1.34.7.sql @@ -0,0 +1,5 @@ +-- +-- This updates a 1.34.6 database to 1.34.7 +-- +-- No changes required +-- diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 60701c429..39d6353f5 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.34.6 +Version: 1.34.7 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 6fef6c580..ca380088a 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.34.6 +1.34.7 From bfa08c342252f6f18f0e5b9246bcc40af4e8150e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2020 13:06:10 -0400 Subject: [PATCH 15/28] MOstly spaces and quotes, remove duplicated db version update and only prepare the sth once. --- scripts/zmupdate.pl.in | 107 +++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index b0b63757a..3662b6655 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -847,9 +847,9 @@ if ( $version ) { } $cascade = !undef; } - if ( $cascade || $version eq "1.24.4" ) { + if ( $cascade || $version eq '1.24.4' ) { # Patch the database - patchDB( $dbh, "1.24.4" ); + patchDB($dbh, '1.24.4'); # Copy the FTP specific values to the new general config my $fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'"; @@ -863,12 +863,12 @@ if ( $version ) { } $cascade = !undef; } - if ( $cascade || $version lt "1.26.0" ) { - my $sth = $dbh->prepare_cached( 'select * from Monitors LIMIT 0,1' ); + if ( $cascade || $version lt '1.26.0' ) { + my $sth = $dbh->prepare_cached('SELECT * FROM Monitors LIMIT 0,1'); die "Error: " . $dbh->errstr . "\n" unless ($sth); die "Error: " . $sth->errstr . "\n" unless ($sth->execute); - my $columns = $sth->{'NAME'}; + my $columns = $sth->{NAME}; if ( ! grep(/^Colours$/, @$columns ) ) { $dbh->do(q{alter table Monitors add column `Colours` tinyint(3) unsigned NOT NULL default '1' after `Height`;}); } # end if @@ -898,28 +898,31 @@ if ( $version ) { die "Should have found upgrade scripts at $updateDir\n"; } # end if + my $sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_DYN_DB_VERSION'"; + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + foreach my $patch ( @files ) { my ( $v ) = $patch =~ /^zm_update\-([\d\.]+)\.sql$/; #PP make sure we use version compare - if ( version->parse('v' . $v) > version->parse('v' . $version) ) { - print( "Upgrading DB to $v from $version\n" ); - patchDB( $dbh, $v ); - my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + if ( version->parse('v'.$v) > version->parse('v'.$version) ) { + print("Upgrading DB to $v from $version\n"); + if ( patchDB($dbh, $v) ) { + my $res = $sth->execute($version) or die( "Can't execute: ".$sth->errstr() ); + } #patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch ); } # end if newer version } # end foreach patchfile + + $sth->finish(); $cascade = !undef; } # end if if ( $cascade ) { - my $installed_version = ZM_VERSION; - my $sql = 'update Config set Value = ? where Name = ?'; + # This is basically here so that we don't need zm-update-blah.sql files for versions without db changes + my $sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( "$installed_version", 'ZM_DYN_DB_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); - $res = $sth->execute( "$installed_version", 'ZM_DYN_CURR_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); + $sth->execute(ZM_VERSION, 'ZM_DYN_DB_VERSION') or die( "Can't execute: ".$sth->errstr() ); + $sth->execute(ZM_VERSION, 'ZM_DYN_CURR_VERSION') or die( "Can't execute: ".$sth->errstr() ); $sth->finish(); } else { zmDbDisconnect(); @@ -930,41 +933,42 @@ if ( $version ) { #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() ); #$sth->finish(); - print( "\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n" ); -} + print("\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n"); +} # end if version + zmDbDisconnect(); -exit( 0 ); +exit(0); sub patchDB_using_do { my ( $dbh, $version, $file ) = @_; - open( my $fh, '<', $file ) or die "Unable to open $file $!"; + open(my $fh, '<', $file) or die "Unable to open $file $!"; $/ = undef; my $sql = <$fh>; close $fh; if ( $sql ) { - $dbh->{'AutoCommit'} = 0; + $dbh->{AutoCommit} = 0; $dbh->do($sql); if ( $dbh->errstr() ) { $dbh->rollback(); - die "Error: " . $dbh->errstr(). ". Rolled back.\n"; + die 'Error: '.$dbh->errstr().". Rolled back.\n"; } # end if error - my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); + my $sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = \'ZM_DYN_DB_VERSION\''; + my $sth = $dbh->prepare_cached($sql) or die "Can't prepare '$sql': ".$dbh->errstr(); + my $res = $sth->execute($version) or die 'Can\'t execute: '.$sth->errstr(); $sth->finish(); - $dbh->{'AutoCommit'} = 1; + $dbh->{AutoCommit} = 1; } else { Warning("Empty db update file at $file"); } -} +} # end sub patchDB_using_do + sub patchDB { my $dbh = shift; my $version = shift; - my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my $command = 'mysql'; if ( defined($portOrSocket) ) { @@ -988,39 +992,38 @@ sub patchDB { } $command .= '/zm_update-'.$version.'.sql'; - print( "Executing '$command'\n" ) if ( logDebugging() ); + print("Executing '$command'\n") if logDebugging(); my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { - chomp( $output ); - print( "Output: $output\n" ); + chomp($output); + print("Output: $output\n"); } if ( $status ) { - die( "Command '$command' exited with status: $status\n" ); + die("Command '$command' exited with status: $status\n"); } - print( "\nDatabase successfully upgraded to version $version.\n" ); - -} + print("\nDatabase successfully upgraded to version $version.\n"); +} # end sub patchDB sub migratePasswords { - print ("Migratings passwords, if any...\n"); - my $sql = "select * from Users"; - 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() ); - while( my $user = $sth->fetchrow_hashref() ) { - my $scheme = substr($user->{Password}, 0, 1); - if ($scheme eq "*") { - print ("-->".$user->{Username}. " password will be migrated\n"); - my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8)); - my $settings = '$2a$10$'.$salt; - my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings); - my $new_pass_hash = "-ZM-".$pass_hash; - $sql = "UPDATE Users SET PASSWORD=? WHERE Username=?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($new_pass_hash, $user->{Username}) or die( "Can't execute: ".$sth->errstr() ); - } + print ("Migratings passwords, if any...\n"); + my $sql = 'SELECT * FROM `Users`'; + 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()); + while( my $user = $sth->fetchrow_hashref() ) { + my $scheme = substr($user->{Password}, 0, 1); + if ($scheme eq '*') { + print ('-->'.$user->{Username}." password will be migrated\n"); + my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8)); + my $settings = '$2a$10$'.$salt; + my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings); + my $new_pass_hash = '-ZM-'.$pass_hash; + $sql = 'UPDATE Users SET `Password`=? WHERE `Username`=?'; + my $sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($new_pass_hash, $user->{Username}) or die("Can't execute: ".$sth->errstr()); } -} + } +} # end sub migratePasswords sub migratePaths { From 4eed0a9c291f69a87f95164f43c89688b5a9b3a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2020 12:43:21 -0400 Subject: [PATCH 16/28] Fix selecting layout after save by using value in session. When applying layout, if height is auto, set the img height to auto. --- web/skins/classic/views/js/montage.js | 9 ++++++--- web/skins/classic/views/montage.php | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index d294ed813..5d3ce33b0 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -210,7 +210,6 @@ function Monitor(monitorData) { * @param {*} element - the event data passed by onchange callback */ function selectLayout(element) { - console.log(element); layout = $j(element).val(); if ( layout_id = parseInt(layout) ) { @@ -221,8 +220,8 @@ function selectLayout(element) { // Need to clear the current positioning, and apply the new monitor_frame = $j('#monitorFrame'+monitor.id); - if ( ! monitor_frame ) { - console.log("Error finding frame for " + monitor.id); + if ( !monitor_frame ) { + console.log('Error finding frame for ' + monitor.id); continue; } @@ -262,6 +261,10 @@ function selectLayout(element) { if ( streamImg.nodeName == 'IMG' ) { var src = streamImg.src; src = src.replace(/width=[\.\d]+/i, 'width=0' ); + if ( $j('#height').val() == 'auto' ) { + src = src.replace(/height=[\.\d]+/i, 'height=0' ); + streamImg.style.height = 'auto'; + } if ( src != streamImg.src ) { streamImg.src = ''; streamImg.src = src; diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index d2cd18323..d6a51732e 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -66,17 +66,19 @@ foreach ( $layouts as $l ) { } } foreach ( $layouts as $l ) { - if ( $l->Name() != "Freeform" ) + if ( $l->Name() != 'Freeform' ) $layoutsById[$l->Id()] = $l; } -session_start(); +zm_session_start(); $layout_id = ''; if ( isset($_COOKIE['zmMontageLayout']) ) { $layout_id = $_SESSION['zmMontageLayout'] = $_COOKIE['zmMontageLayout']; -#} elseif ( isset($_SESSION['zmMontageLayout']) ) { - #$layout_id = $_SESSION['zmMontageLayout']; + ZM\Logger::Debug("Using layout $layout_id"); +} elseif ( isset($_SESSION['zmMontageLayout']) ) { + $layout_id = $_SESSION['zmMontageLayout']; + ZM\Logger::Debug("Using layout $layout_id from session"); } $options = array(); @@ -85,6 +87,8 @@ $Positions = ''; if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) ) { $Layout = $layoutsById[$layout_id]; $Positions = json_decode($Layout->Positions(), true); +} else { + ZM\Logger::Debug("Layout not found"); } if ( $Layout and ( $Layout->Name() != 'Freeform' ) ) { // Use layout instead of other options From c3bcdcff6426726397c3b3e5d93fe89bc9356fe1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2020 13:05:12 -0400 Subject: [PATCH 17/28] Use zm_session_start instead of session_start --- web/includes/actions/montage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/actions/montage.php b/web/includes/actions/montage.php index 207c9a0f0..cd9a41aaf 100644 --- a/web/includes/actions/montage.php +++ b/web/includes/actions/montage.php @@ -36,7 +36,7 @@ if ( isset($_REQUEST['object']) ) { } $Layout->Positions($_REQUEST['Positions']); $Layout->save(); - session_start(); + zm_session_start(); $_SESSION['zmMontageLayout'] = $Layout->Id(); setcookie('zmMontageLayout', $Layout->Id(), 1); session_write_close(); From ae80b3b8595599bbf7255e836c394dcd410808aa Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Wed, 25 Mar 2020 23:21:34 -0700 Subject: [PATCH 18/28] Start implementing VNC --- db/zm_create.sql.in | 6 +- src/CMakeLists.txt | 2 +- src/zm_camera.h | 3 +- src/zm_libvnc_camera.cpp | 128 ++++++++++++++++++++++++++++ src/zm_libvnc_camera.h | 64 ++++++++++++++ src/zm_monitor.cpp | 19 +++++ src/zm_monitor.h | 1 + web/api/app/Model/Monitor.php | 2 +- web/skins/classic/views/monitor.php | 14 ++- 9 files changed, 230 insertions(+), 9 deletions(-) create mode 100644 src/zm_libvnc_camera.cpp create mode 100644 src/zm_libvnc_camera.h diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index ce504a422..ce462ac4c 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -63,7 +63,7 @@ DROP TABLE IF EXISTS `Controls`; CREATE TABLE `Controls` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', - `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket') NOT NULL default 'Local', + `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket','VNC') NOT NULL default 'Local', `Protocol` varchar(64) default NULL, `CanWake` tinyint(3) unsigned NOT NULL default '0', `CanSleep` tinyint(3) unsigned NOT NULL default '0', @@ -406,7 +406,7 @@ DROP TABLE IF EXISTS `MonitorPresets`; CREATE TABLE `MonitorPresets` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', - `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket') NOT NULL default 'Local', + `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket','VNC') NOT NULL default 'Local', `Device` tinytext, `Channel` tinyint(3) unsigned default NULL, `Format` int(10) unsigned default NULL, @@ -440,7 +440,7 @@ CREATE TABLE `Monitors` ( `Notes` TEXT, `ServerId` int(10) unsigned, `StorageId` smallint(5) unsigned default 0, - `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket') NOT NULL default 'Local', + `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', `LinkedMonitors` varchar(255), diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 331f9e039..2f75c5c04 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY) # Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc) -set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_frame.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_input.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp zm_fifo.cpp zm_crypt.cpp) +set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_frame.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_input.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_libvnc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp zm_fifo.cpp zm_crypt.cpp) # A fix for cmake recompiling the source files for every target. diff --git a/src/zm_camera.h b/src/zm_camera.h index a6f576af2..2742ef1d8 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -35,7 +35,7 @@ class Camera; // class Camera { protected: - typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC } SourceType; + typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC, VNC_SRC } SourceType; unsigned int monitor_id; Monitor * monitor; // Null on instantiation, set as soon as possible. @@ -68,6 +68,7 @@ public: bool IsFfmpeg() const { return type == FFMPEG_SRC; } bool IsLibvlc() const { return type == LIBVLC_SRC; } bool IscURL() const { return type == CURL_SRC; } + bool IsVNC() const { return type == VNC_SRC; } unsigned int Width() const { return width; } unsigned int Height() const { return height; } unsigned int Colours() const { return colours; } diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp new file mode 100644 index 000000000..efd2954cd --- /dev/null +++ b/src/zm_libvnc_camera.cpp @@ -0,0 +1,128 @@ +#include "zm.h" +#include "zm_signal.h" +#include "zm_libvnc_camera.h" + +static int TAG_0; +static int TAG_1; +static int TAG_2; + +static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, int h){ + VncPrivateData *data = (VncPrivateData *)rfbClientGetClientData(rfb, &TAG_0); + data->buffer = rfb->frameBuffer; +} + +static char* GetPasswordCallback(rfbClient* cl){ + return strdup((const char *)rfbClientGetClientData(cl, &TAG_1)); +} + +static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ + rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential)); + if(credentialType != rfbCredentialTypeUser) { + return NULL; + } + + c->userCredential.password = strdup((const char *)rfbClientGetClientData(cl, &TAG_1)); + c->userCredential.username = strdup((const char *)rfbClientGetClientData(cl, &TAG_2)); + return c; +} + +VncCamera::VncCamera( + unsigned int p_monitor_id, + const std::string &host, + const std::string &port, + const std::string &user, + const std::string &pass, + int p_width, + int p_height, + int p_colours, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio ) : + Camera( + p_monitor_id, + VNC_SRC, + p_width, + p_height, + p_colours, + ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), + p_brightness, + p_contrast, + p_hue, + p_colour, + p_capture, + p_record_audio + ), + mHost(host), + mPort(port), + mUser(user), + mPass(pass) +{ + Debug(2, "Host:%s Port: %s User: %s Pass:%s", mHost.c_str(), mPort.c_str(), mUser.c_str(), mPass.c_str()); + if( capture ) + Initialise(); +} + + +VncCamera::~VncCamera() { + if( capture ) + Terminate(); +} + +void VncCamera::Initialise() { + Debug(2, "Initializing Client"); + mRfb = rfbGetClient(8, 3, 4); + rfbClientSetClientData(mRfb, &TAG_0, &mVncData); + rfbClientSetClientData(mRfb, &TAG_1, (void *)mPass.c_str()); + rfbClientSetClientData(mRfb, &TAG_2, (void *)mUser.c_str()); + + mVncData.bufferSize = width * height * 4; + mVncData.buffer = (uint8_t *)malloc(mVncData.bufferSize * sizeof(uint8_t)); + + mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback; + mRfb->GetPassword = GetPasswordCallback; + mRfb->GetCredential = GetCredentialsCallback; + + mRfb->programName = "Zoneminder VNC Monitor"; + mRfb->serverHost = strdup(mHost.c_str()); + mRfb->serverPort = atoi(mPort.c_str()); + rfbInitClient(mRfb, 0, nullptr); +} + +void VncCamera::Terminate() { + if(mVncData.buffer) + free(mVncData.buffer); + return; +} + +int VncCamera::PrimeCapture() { + Info("Priming capture from %s", mHost.c_str()); + return 0; +} + +int VncCamera::PreCapture() { + WaitForMessage(mRfb, 500); + rfbBool res = HandleRFBServerMessage(mRfb); + return res == TRUE ? 1 : -1 ; +} + +int VncCamera::Capture(Image &image) { + Debug(2, "Capturing"); + image.Assign(width, height, colours, subpixelorder, mVncData.buffer, width * height * 4); + return 1; +} + +int VncCamera::PostCapture() { + return 0; +} + +int VncCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) { + return 0; +} + +int VncCamera::Close() { + rfbClientCleanup(mRfb); + return 0; +} \ No newline at end of file diff --git a/src/zm_libvnc_camera.h b/src/zm_libvnc_camera.h new file mode 100644 index 000000000..667111bc5 --- /dev/null +++ b/src/zm_libvnc_camera.h @@ -0,0 +1,64 @@ + +#ifndef ZN_LIBVNC_CAMERA_H +#define ZN_LIBVNC_CAMERA_H + +#include "zm_buffer.h" +#include "zm_camera.h" +#include "zm_thread.h" + +#include + +// Used by vnc callbacks +struct VncPrivateData +{ + uint8_t *buffer; + uint8_t *prevBuffer; + uint32_t bufferSize; + Mutex mutex; + ThreadData newImage; +}; + +class VncCamera : public Camera { +protected: + rfbClient *mRfb; + VncPrivateData mVncData; + int mBpp; + int mSpp; + int mBps; + char** mOptArgvs; + std::string mHost; + std::string mPort; + std::string mUser; + std::string mPass; + time_t secs; +public: + VncCamera( + unsigned int p_monitor_id, + const std::string &host, + const std::string &port, + const std::string &user, + const std::string &pass, + int p_width, + int p_height, + int p_colours, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio ); + + ~VncCamera(); + + void Initialise(); + void Terminate(); + + int PreCapture(); + int PrimeCapture(); + int Capture( Image &image ); + int PostCapture(); + int CaptureAndRecord( Image &image, timeval recording, char* event_directory ); + int Close(); +}; + +#endif \ No newline at end of file diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 2f0e4826b..291fe039d 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -51,6 +51,7 @@ #if HAVE_LIBCURL #include "zm_curl_camera.h" #endif // HAVE_LIBCURL +#include "zm_libvnc_camera.h" #if ZM_MEM_MAPPED #include @@ -89,6 +90,7 @@ std::string CameraType_Strings[] = { "Ffmpeg", "LibVLC", "CURL", + "VNC", }; @@ -2332,6 +2334,23 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { #else // HAVE_LIBCURL Fatal("You must have libcurl installed to use ffmpeg cameras for monitor %d", id); #endif // HAVE_LIBCURL + } else if ( type == "VNC" ) { + camera = new VncCamera( + id, + host.c_str(), + port.c_str(), + user.c_str(), + pass.c_str(), + width, + height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); } else { Fatal("Bogus monitor type '%s' for monitor %d", type.c_str(), id); } // end if type diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 9109c9c72..e1d66950c 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -75,6 +75,7 @@ public: FFMPEG, LIBVLC, CURL, + VNC, } CameraType; typedef enum { diff --git a/web/api/app/Model/Monitor.php b/web/api/app/Model/Monitor.php index aa959f429..2de0b6fcb 100644 --- a/web/api/app/Model/Monitor.php +++ b/web/api/app/Model/Monitor.php @@ -119,7 +119,7 @@ class Monitor extends AppModel { ); public $actsAs = array( 'CakePHP-Enum-Behavior.Enum' => array( - 'Type' => array('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite'), + 'Type' => array('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite', 'VNC'), 'Function' => array('None','Monitor','Modect','Record','Mocord','Nodect'), 'Orientation' => array('ROTATE_0','ROTATE_90','ROTATE_180','ROTATE_270','FLIP_HORI','FLIP_VERT'), 'OutputCodec' => array('h264','mjpeg','mpeg1','mpeg2'), diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 81ab90b96..b3a2dfc79 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -123,7 +123,8 @@ $sourceTypes = array( 'Libvlc' => translate('Libvlc'), 'cURL' => 'cURL (HTTP(S) only)', 'WebSite'=> 'Web Site', - 'NVSocket' => translate('NVSocket') + 'NVSocket' => translate('NVSocket'), + 'VNC' => 'VNC' ); if ( !ZM_HAS_V4L ) unset($sourceTypes['Local']); @@ -779,6 +780,13 @@ switch ( $tab ) { } else if ( $monitor->Type() == 'NVSocket' ) { include('_monitor_source_nvsocket.php'); + } else if ( $monitor->Type() == 'VNC' ) { +?> + + + + +Type() == 'Remote' ) { ?> Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?> @@ -811,8 +819,8 @@ include('_monitor_source_nvsocket.php'); ?> () - () - + () + Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { ?> From 457f3e41beeafd9db4c80241030b8b4ad370d05b Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Wed, 25 Mar 2020 23:29:22 -0700 Subject: [PATCH 19/28] Add cmake rules to check for libvnc --- CMakeLists.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index df1702328..dfc1f7b75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,8 @@ set(ZM_NO_MMAP "OFF" CACHE BOOL experience problems with the shared memory. default: OFF") set(ZM_NO_LIBVLC "OFF" CACHE BOOL "Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF") +set(ZM_NO_LIBVNC "OFF" CACHE BOOL +"Set to ON to skip libvnc checks and force building ZM without libvnc. default: OFF") set(ZM_NO_CURL "OFF" CACHE BOOL "Set to ON to skip cURL checks and force building ZM without cURL. default: OFF") set(ZM_NO_X10 "OFF" CACHE BOOL @@ -674,6 +676,25 @@ if(NOT ZM_NO_LIBVLC) endif(LIBVLC_LIBRARIES) endif(NOT ZM_NO_LIBVLC) +if(NOT ZM_NO_LIBVNC) + # libvncclient (using find_library and find_path) + find_library(LIBVNC_LIBRARIES vncclient) + if(LIBVNC_LIBRARIES) + set(HAVE_LIBVNC 1) + list(APPEND ZM_BIN_LIBS "${LIBVNC_LIBRARIES}") + find_path(LIBVNC_INCLUDE_DIR "rfb/rfb.h") + if(LIBVNC_INCLUDE_DIR) + include_directories("${LIBVNC_INCLUDE_DIR}") + set(CMAKE_REQUIRED_INCLUDES "${LIBVNC_INCLUDE_DIR}") + endif(LIBVNC_INCLUDE_DIR) + mark_as_advanced(FORCE LIBVNC_LIBRARIES LIBVNC_INCLUDE_DIR) + check_include_file("rfb/rfb.h" HAVE_RFB_RFB_H) + set(optlibsfound "${optlibsfound} libVNC") + else(LIBVNC_LIBRARIES) + set(optlibsnotfound "${optlibsnotfound} libVNC") + endif(LIBVNC_LIBRARIES) +endif(NOT ZM_NO_LIBVNC) + #find_package(Boost 1.36.0) #if(Boost_FOUND) #include_directories(${Boost_INCLUDE_DIRS}) From d61e5e42ca58b693fc4fe74bc75b7f00ab990ff4 Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Thu, 26 Mar 2020 00:08:00 -0700 Subject: [PATCH 20/28] Use preprocessors to ensure libvnc monitor is only built when libvnc is found --- src/zm_libvnc_camera.cpp | 5 ++++- src/zm_libvnc_camera.h | 3 ++- src/zm_monitor.cpp | 6 ++++++ zoneminder-config.cmake | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index efd2954cd..c72b0b340 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -2,6 +2,8 @@ #include "zm_signal.h" #include "zm_libvnc_camera.h" +#if HAVE_LIBVNC + static int TAG_0; static int TAG_1; static int TAG_2; @@ -125,4 +127,5 @@ int VncCamera::CaptureAndRecord(Image &image, timeval recording, char* event_dir int VncCamera::Close() { rfbClientCleanup(mRfb); return 0; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/zm_libvnc_camera.h b/src/zm_libvnc_camera.h index 667111bc5..6d9285114 100644 --- a/src/zm_libvnc_camera.h +++ b/src/zm_libvnc_camera.h @@ -6,6 +6,7 @@ #include "zm_camera.h" #include "zm_thread.h" +#if HAVE_LIBVNC #include // Used by vnc callbacks @@ -61,4 +62,4 @@ public: int Close(); }; -#endif \ No newline at end of file +#endif // HAVE_LIBVNC diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 291fe039d..1186c75f7 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -51,7 +51,9 @@ #if HAVE_LIBCURL #include "zm_curl_camera.h" #endif // HAVE_LIBCURL +#if HAVE_LIBVNC #include "zm_libvnc_camera.h" +#endif // HAVE_LIBVNC #if ZM_MEM_MAPPED #include @@ -2335,6 +2337,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { Fatal("You must have libcurl installed to use ffmpeg cameras for monitor %d", id); #endif // HAVE_LIBCURL } else if ( type == "VNC" ) { +#if HAVE_LIBVNC camera = new VncCamera( id, host.c_str(), @@ -2351,6 +2354,9 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { purpose==CAPTURE, record_audio ); +#else // HAVE_LIBVNC + Fatal("You must have libvnc installed to use VNC cameras for monitor id %d", id); +#endif // HAVE_LIBVNC } else { Fatal("Bogus monitor type '%s' for monitor %d", type.c_str(), id); } // end if type diff --git a/zoneminder-config.cmake b/zoneminder-config.cmake index 320620aa0..edcb42ff6 100644 --- a/zoneminder-config.cmake +++ b/zoneminder-config.cmake @@ -59,6 +59,8 @@ #cmakedefine HAVE_LIBAVRESAMPLE_AVRESAMPLE_H 1 #cmakedefine HAVE_LIBVLC 1 #cmakedefine HAVE_VLC_VLC_H 1 +#cmakedefine HAVE_LIBVNC 1 +#cmakedefine HAVE_RFB_RFB_H 1 #cmakedefine HAVE_LIBX264 1 #cmakedefine HAVE_X264_H 1 #cmakedefine HAVE_LIBMP4V2 1 From b615eada41b2f0308a4dcba8b96899a0a734bdce Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Thu, 26 Mar 2020 00:52:34 -0700 Subject: [PATCH 21/28] Add a missing endif --- src/zm_libvnc_camera.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_libvnc_camera.h b/src/zm_libvnc_camera.h index 6d9285114..f57d12813 100644 --- a/src/zm_libvnc_camera.h +++ b/src/zm_libvnc_camera.h @@ -63,3 +63,4 @@ public: }; #endif // HAVE_LIBVNC +#endif // ZN_LIBVNC_CAMERA_H From a781cc2c87c46ee56665c5dece3b58656e5a7e66 Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Fri, 27 Mar 2020 11:15:15 -0700 Subject: [PATCH 22/28] WIP scaling --- src/zm_libvnc_camera.cpp | 53 ++++++++++++++++++++++++++--- src/zm_libvnc_camera.h | 11 +++--- web/skins/classic/views/monitor.php | 2 +- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index c72b0b340..a9863f450 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -1,6 +1,11 @@ #include "zm.h" #include "zm_signal.h" #include "zm_libvnc_camera.h" +extern "C" { + #include + #include + #include +} #if HAVE_LIBVNC @@ -76,13 +81,11 @@ VncCamera::~VncCamera() { void VncCamera::Initialise() { Debug(2, "Initializing Client"); mRfb = rfbGetClient(8, 3, 4); + rfbClientSetClientData(mRfb, &TAG_0, &mVncData); rfbClientSetClientData(mRfb, &TAG_1, (void *)mPass.c_str()); rfbClientSetClientData(mRfb, &TAG_2, (void *)mUser.c_str()); - mVncData.bufferSize = width * height * 4; - mVncData.buffer = (uint8_t *)malloc(mVncData.bufferSize * sizeof(uint8_t)); - mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback; mRfb->GetPassword = GetPasswordCallback; mRfb->GetCredential = GetCredentialsCallback; @@ -94,13 +97,15 @@ void VncCamera::Initialise() { } void VncCamera::Terminate() { - if(mVncData.buffer) - free(mVncData.buffer); return; } int VncCamera::PrimeCapture() { Info("Priming capture from %s", mHost.c_str()); + if(mRfb->si.framebufferWidth != width || mRfb->si.framebufferHeight != height) { + Info("Expected screen resolution does not match with the provided resolution, using scaling"); + mScale = true; + } return 0; } @@ -112,11 +117,49 @@ int VncCamera::PreCapture() { int VncCamera::Capture(Image &image) { Debug(2, "Capturing"); + int srcLineSize[4]; + int dstLineSize[4]; + int dstSize; + if(mScale) { + sws = sws_getContext(mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, AV_PIX_FMT_RGBA, + width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); + if(!sws) { + Error("Could not scale image"); + return -1; + } + + if (av_image_fill_arrays(srcbuf, srcLineSize, mVncData.buffer, AV_PIX_FMT_RGBA, + mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, 16) < 0) { + sws_freeContext(sws); + Error("Could not allocate source image. Scaling failed"); + return -1; + } + + if ((dstSize = av_image_alloc(dstbuf, dstLineSize, width, height, + AV_PIX_FMT_RGBA, 1)) < 0) { + av_freep(&srcbuf[0]); + sws_freeContext(sws); + Error("Could not allocate dest image. Scaling failed"); + return -1; + } + + sws_scale(sws, (const uint8_t* const*)srcbuf, srcLineSize, 0, mRfb->si.framebufferHeight, + dstbuf, dstLineSize); + + } + else{ + dstbuf[0] = mVncData.buffer; + } image.Assign(width, height, colours, subpixelorder, mVncData.buffer, width * height * 4); return 1; } int VncCamera::PostCapture() { + if(mScale) { + av_freep(&srcbuf[0]); + av_freep(&dstbuf[0]); + sws_freeContext(sws); + } return 0; } diff --git a/src/zm_libvnc_camera.h b/src/zm_libvnc_camera.h index f57d12813..9502f8330 100644 --- a/src/zm_libvnc_camera.h +++ b/src/zm_libvnc_camera.h @@ -13,10 +13,8 @@ struct VncPrivateData { uint8_t *buffer; - uint8_t *prevBuffer; - uint32_t bufferSize; - Mutex mutex; - ThreadData newImage; + uint8_t width; + uint8_t height; }; class VncCamera : public Camera { @@ -26,12 +24,13 @@ protected: int mBpp; int mSpp; int mBps; - char** mOptArgvs; + bool mScale; + uint8_t *srcbuf[4], *dstbuf[4]; + struct SwsContext *sws; std::string mHost; std::string mPort; std::string mUser; std::string mPass; - time_t secs; public: VncCamera( unsigned int p_monitor_id, diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index b3a2dfc79..6e08cd072 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -785,7 +785,7 @@ include('_monitor_source_nvsocket.php'); - + Type() == 'Remote' ) { ?> From fc25a777fd3393f723b308d80cf0e813050b0c9c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2020 14:47:59 -0400 Subject: [PATCH 23/28] Bump version for db update adding VNC Monitor Type --- db/zm_update-1.35.2.sql | 1 + version | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 db/zm_update-1.35.2.sql diff --git a/db/zm_update-1.35.2.sql b/db/zm_update-1.35.2.sql new file mode 100644 index 000000000..b94ab38c5 --- /dev/null +++ b/db/zm_update-1.35.2.sql @@ -0,0 +1 @@ +ALTER TABLE Monitors MODIFY `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','NVSocket','VNC') NOT NULL default 'Local'; diff --git a/version b/version index 7eee78574..0035f2a76 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.35.1 +1.35.2 From dd9c578be6e21fff6707a769ecfbf5b5872043c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2020 14:48:20 -0400 Subject: [PATCH 24/28] bumpv ersion to 1.35.2 --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index d3ffad793..923e0c068 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.35.1 +Version: 1.35.2 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons From 599960ef056a023e83977987fdd258b7e4e856cd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 28 Mar 2020 10:09:13 -0400 Subject: [PATCH 25/28] Update group save action, using Group object methods. Fixes errors on new MariaDB --- web/includes/actions/group.php | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/web/includes/actions/group.php b/web/includes/actions/group.php index 9aa988540..b23659d18 100644 --- a/web/includes/actions/group.php +++ b/web/includes/actions/group.php @@ -21,42 +21,31 @@ // Group edit actions # Should probably verify that each monitor id is a valid monitor, that we have access to. # However at the moment, you have to have System permissions to do this -if ( ! canEdit('Groups') ) { +if ( !canEdit('Groups') ) { ZM\Warning('Need group edit permissions to edit groups'); return; } if ( $action == 'Save' ) { - $monitors = empty($_POST['newGroup']['MonitorIds']) ? '' : implode(',', $_POST['newGroup']['MonitorIds']); $group_id = null; - if ( !empty($_POST['gid']) ) { + if ( !empty($_POST['gid']) ) $group_id = $_POST['gid']; - dbQuery( - 'UPDATE Groups SET Name=?, ParentId=? WHERE Id=?', + $group = new ZM\Group($group_id); + $group->save( array( - $_POST['newGroup']['Name'], - ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), - $group_id, + 'Name'=> $_POST['newGroup']['Name'], + 'ParentId'=>( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), ) ); - dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($group_id)); - } else { - dbQuery( - 'INSERT INTO Groups (Name,ParentId) VALUES (?,?)', - array( - $_POST['newGroup']['Name'], - ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), - ) - ); - $group_id = dbInsertId(); - } + dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id)); + $group_id = $group->Id(); if ( $group_id ) { foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) { - dbQuery('INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($group_id, $mid)); + dbQuery('INSERT INTO `Groups_Monitors` (`GroupId`,`MonitorId`) VALUES (?,?)', array($group_id, $mid)); } } $view = 'none'; $refreshParent = true; $closePopup = true; -} +} ?> From 38c018ed18bad71caee66c1dcffaadde5c644107 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 28 Mar 2020 11:19:06 -0400 Subject: [PATCH 26/28] Add a warning when an email exceeds 10Mb --- scripts/zmfilter.pl.in | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 18b08cdf1..5b478316d 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -829,14 +829,20 @@ sub sendEmail { Data => $body ); ### Add the attachments + my $total_size = 0; foreach my $attachment ( @attachments ) { - Info("Attaching '$attachment->{path}'"); + my $size = -s $attachment->{path}; + $total_size += $size; + Info("Attaching '$attachment->{path}' which is $size bytes"); $mail->attach( Path => $attachment->{path}, Type => $attachment->{type}, Disposition => 'attachment' ); } + if ( $total_size > 10*1024*1024 ) { + Warning('Emails larger than 10Mb will often not be delivered! This one is '.int($total_size/(1024*1024)).'Mb'); + } ### Send the Message if ( $Config{ZM_SSMTP_MAIL} ) { my $ssmtp_location = $Config{ZM_SSMTP_PATH}; @@ -860,20 +866,27 @@ sub sendEmail { } } else { my $mail = MIME::Entity->build( - From => $Config{ZM_FROM_EMAIL}, - To => $$filter{EmailTo}, - Subject => $subject, - Type => (($body=~/ $body - ); + From => $Config{ZM_FROM_EMAIL}, + To => $$filter{EmailTo}, + Subject => $subject, + Type => (($body=~/ $body + ); + my $total_size = 0; foreach my $attachment ( @attachments ) { - Info("Attaching '$attachment->{path}'"); + my $size = -s $attachment->{path}; + $total_size += $size; + Info("Attaching '$attachment->{path}' which is $size bytes"); + $mail->attach( - Path => $attachment->{path}, - Type => $attachment->{type}, - Encoding => 'base64' - ); + Path => $attachment->{path}, + Type => $attachment->{type}, + Encoding => 'base64' + ); + } # end foreach attachment + if ( $total_size > 10*1024*1024 ) { + Warning('Emails larger than 10Mb will often not be delivered! This one is '.int($total_size/(1024*1024)).'Mb'); } $mail->smtpsend(Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL}); } From e894102cb7c65a7c239e98d87477b1f9de00beee Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 28 Mar 2020 11:59:05 -0400 Subject: [PATCH 27/28] debug --- src/zm_libvnc_camera.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index a9863f450..6bc62d7c0 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -110,8 +110,11 @@ int VncCamera::PrimeCapture() { } int VncCamera::PreCapture() { + Debug(2, "PreCapture"); WaitForMessage(mRfb, 500); + Debug(2, "After Wait "); rfbBool res = HandleRFBServerMessage(mRfb); + Debug(2, "After Handle "); return res == TRUE ? 1 : -1 ; } @@ -120,10 +123,12 @@ int VncCamera::Capture(Image &image) { int srcLineSize[4]; int dstLineSize[4]; int dstSize; - if(mScale) { - sws = sws_getContext(mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, AV_PIX_FMT_RGBA, - width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); - if(!sws) { + if ( mScale ) { + sws = sws_getContext( + mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, AV_PIX_FMT_RGBA, + width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, + NULL, NULL, NULL); + if ( !sws ) { Error("Could not scale image"); return -1; } @@ -171,4 +176,4 @@ int VncCamera::Close() { rfbClientCleanup(mRfb); return 0; } -#endif \ No newline at end of file +#endif From b93f5d970cc467a0647df6231275479f05029539 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 28 Mar 2020 16:03:52 -0400 Subject: [PATCH 28/28] sws_scale directly into the image. Allocate and de-allocate sws in Prime and Close. Seems to fix scaling. --- src/zm_libvnc_camera.cpp | 67 +++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index 6bc62d7c0..b18ebda97 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -24,7 +24,7 @@ static char* GetPasswordCallback(rfbClient* cl){ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential)); - if(credentialType != rfbCredentialTypeUser) { + if ( credentialType != rfbCredentialTypeUser ) { return NULL; } @@ -68,7 +68,7 @@ VncCamera::VncCamera( mPass(pass) { Debug(2, "Host:%s Port: %s User: %s Pass:%s", mHost.c_str(), mPort.c_str(), mUser.c_str(), mPass.c_str()); - if( capture ) + if ( capture ) Initialise(); } @@ -102,9 +102,18 @@ void VncCamera::Terminate() { int VncCamera::PrimeCapture() { Info("Priming capture from %s", mHost.c_str()); - if(mRfb->si.framebufferWidth != width || mRfb->si.framebufferHeight != height) { - Info("Expected screen resolution does not match with the provided resolution, using scaling"); + if ( mRfb->si.framebufferWidth != width || mRfb->si.framebufferHeight != height ) { + Info("Expected screen resolution (%dx%d) does not match the provided resolution (%dx%d), using scaling", + width, height, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight); mScale = true; + sws = sws_getContext( + mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, AV_PIX_FMT_RGBA, + width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, + NULL, NULL, NULL); + if ( !sws ) { + Error("Could not scale image"); + return -1; + } } return 0; } @@ -123,48 +132,39 @@ int VncCamera::Capture(Image &image) { int srcLineSize[4]; int dstLineSize[4]; int dstSize; + if ( mScale ) { - sws = sws_getContext( - mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, AV_PIX_FMT_RGBA, - width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, - NULL, NULL, NULL); - if ( !sws ) { - Error("Could not scale image"); + uint8_t* directbuffer; + + /* Request a writeable buffer of the target image */ + directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); + if ( directbuffer == NULL ) { + Error("Failed requesting writeable buffer for the captured image."); return -1; } - if (av_image_fill_arrays(srcbuf, srcLineSize, mVncData.buffer, AV_PIX_FMT_RGBA, + if ( av_image_fill_arrays(dstbuf, dstLineSize, directbuffer, AV_PIX_FMT_RGBA, + width, height, 16) < 0) { + Error("Could not allocate dst image. Scaling failed"); + return -1; + } + + if ( av_image_fill_arrays(srcbuf, srcLineSize, mVncData.buffer, AV_PIX_FMT_RGBA, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, 16) < 0) { - sws_freeContext(sws); Error("Could not allocate source image. Scaling failed"); return -1; } - if ((dstSize = av_image_alloc(dstbuf, dstLineSize, width, height, - AV_PIX_FMT_RGBA, 1)) < 0) { - av_freep(&srcbuf[0]); - sws_freeContext(sws); - Error("Could not allocate dest image. Scaling failed"); - return -1; - } - sws_scale(sws, (const uint8_t* const*)srcbuf, srcLineSize, 0, mRfb->si.framebufferHeight, dstbuf, dstLineSize); + } else { + image.Assign(width, height, colours, subpixelorder, mVncData.buffer, width * height * 4); } - else{ - dstbuf[0] = mVncData.buffer; - } - image.Assign(width, height, colours, subpixelorder, mVncData.buffer, width * height * 4); return 1; } int VncCamera::PostCapture() { - if(mScale) { - av_freep(&srcbuf[0]); - av_freep(&dstbuf[0]); - sws_freeContext(sws); - } return 0; } @@ -173,6 +173,15 @@ int VncCamera::CaptureAndRecord(Image &image, timeval recording, char* event_dir } int VncCamera::Close() { +#if HAVE_LIBSWSCALE + if ( mScale ) { + av_freep(&srcbuf[0]); + av_freep(&dstbuf[0]); + sws_freeContext(sws); + sws = NULL; + } +#endif + rfbClientCleanup(mRfb); return 0; }