Merge pull request #1 from connortechnology/libvnc

Libvnc
This commit is contained in:
Kartik 2020-03-28 13:09:17 -07:00 committed by GitHub
commit ba8d9ee768
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 194 additions and 159 deletions

5
db/zm_update-1.34.7.sql Normal file
View File

@ -0,0 +1,5 @@
--
-- This updates a 1.34.6 database to 1.34.7
--
-- No changes required
--

1
db/zm_update-1.35.2.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE Monitors MODIFY `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','NVSocket','VNC') NOT NULL default 'Local';

View File

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

View File

@ -829,14 +829,20 @@ sub sendEmail {
Data => $body Data => $body
); );
### Add the attachments ### Add the attachments
my $total_size = 0;
foreach my $attachment ( @attachments ) { 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( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Disposition => 'attachment' 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 ### Send the Message
if ( $Config{ZM_SSMTP_MAIL} ) { if ( $Config{ZM_SSMTP_MAIL} ) {
my $ssmtp_location = $Config{ZM_SSMTP_PATH}; my $ssmtp_location = $Config{ZM_SSMTP_PATH};
@ -867,13 +873,20 @@ sub sendEmail {
Data => $body Data => $body
); );
my $total_size = 0;
foreach my $attachment ( @attachments ) { 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( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Encoding => 'base64' 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}); $mail->smtpsend(Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL});
} }

View File

@ -847,9 +847,9 @@ if ( $version ) {
} }
$cascade = !undef; $cascade = !undef;
} }
if ( $cascade || $version eq "1.24.4" ) { if ( $cascade || $version eq '1.24.4' ) {
# Patch the database # Patch the database
patchDB( $dbh, "1.24.4" ); patchDB($dbh, '1.24.4');
# Copy the FTP specific values to the new general config # Copy the FTP specific values to the new general config
my $fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'"; my $fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'";
@ -863,12 +863,12 @@ if ( $version ) {
} }
$cascade = !undef; $cascade = !undef;
} }
if ( $cascade || $version lt "1.26.0" ) { if ( $cascade || $version lt '1.26.0' ) {
my $sth = $dbh->prepare_cached( 'select * from Monitors LIMIT 0,1' ); my $sth = $dbh->prepare_cached('SELECT * FROM Monitors LIMIT 0,1');
die "Error: " . $dbh->errstr . "\n" unless ($sth); die "Error: " . $dbh->errstr . "\n" unless ($sth);
die "Error: " . $sth->errstr . "\n" unless ($sth->execute); die "Error: " . $sth->errstr . "\n" unless ($sth->execute);
my $columns = $sth->{'NAME'}; my $columns = $sth->{NAME};
if ( ! grep(/^Colours$/, @$columns ) ) { if ( ! grep(/^Colours$/, @$columns ) ) {
$dbh->do(q{alter table Monitors add column `Colours` tinyint(3) unsigned NOT NULL default '1' after `Height`;}); $dbh->do(q{alter table Monitors add column `Colours` tinyint(3) unsigned NOT NULL default '1' after `Height`;});
} # end if } # end if
@ -898,28 +898,31 @@ if ( $version ) {
die "Should have found upgrade scripts at $updateDir\n"; die "Should have found upgrade scripts at $updateDir\n";
} # end if } # 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 ) { foreach my $patch ( @files ) {
my ( $v ) = $patch =~ /^zm_update\-([\d\.]+)\.sql$/; my ( $v ) = $patch =~ /^zm_update\-([\d\.]+)\.sql$/;
#PP make sure we use version compare #PP make sure we use version compare
if ( version->parse('v' . $v) > version->parse('v' . $version) ) { if ( version->parse('v'.$v) > version->parse('v'.$version) ) {
print( "Upgrading DB to $v from $version\n" ); print("Upgrading DB to $v from $version\n");
patchDB( $dbh, $v ); if ( patchDB($dbh, $v) ) {
my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; my $res = $sth->execute($version) or die( "Can't execute: ".$sth->errstr() );
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();
#patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch ); #patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch );
} # end if newer version } # end if newer version
} # end foreach patchfile } # end foreach patchfile
$sth->finish();
$cascade = !undef; $cascade = !undef;
} # end if } # end if
if ( $cascade ) { if ( $cascade ) {
my $installed_version = ZM_VERSION; # 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 $sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = ?';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); 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() ); $sth->execute(ZM_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_CURR_VERSION') or die( "Can't execute: ".$sth->errstr() );
$sth->finish(); $sth->finish();
} else { } else {
zmDbDisconnect(); zmDbDisconnect();
@ -930,41 +933,42 @@ if ( $version ) {
#my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); #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 $res = $sth->execute( ) or die( "Can't execute: ".$sth->errstr() );
#$sth->finish(); #$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(); zmDbDisconnect();
exit( 0 ); exit(0);
sub patchDB_using_do { sub patchDB_using_do {
my ( $dbh, $version, $file ) = @_; 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; $/ = undef;
my $sql = <$fh>; my $sql = <$fh>;
close $fh; close $fh;
if ( $sql ) { if ( $sql ) {
$dbh->{'AutoCommit'} = 0; $dbh->{AutoCommit} = 0;
$dbh->do($sql); $dbh->do($sql);
if ( $dbh->errstr() ) { if ( $dbh->errstr() ) {
$dbh->rollback(); $dbh->rollback();
die "Error: " . $dbh->errstr(). ". Rolled back.\n"; die 'Error: '.$dbh->errstr().". Rolled back.\n";
} # end if error } # end if error
my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; 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 $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 $res = $sth->execute($version) or die 'Can\'t execute: '.$sth->errstr();
$sth->finish(); $sth->finish();
$dbh->{'AutoCommit'} = 1; $dbh->{AutoCommit} = 1;
} else { } else {
Warning("Empty db update file at $file"); Warning("Empty db update file at $file");
} }
} } # end sub patchDB_using_do
sub patchDB { sub patchDB {
my $dbh = shift; my $dbh = shift;
my $version = shift; my $version = shift;
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
my $command = 'mysql'; my $command = 'mysql';
if ( defined($portOrSocket) ) { if ( defined($portOrSocket) ) {
@ -988,39 +992,38 @@ sub patchDB {
} }
$command .= '/zm_update-'.$version.'.sql'; $command .= '/zm_update-'.$version.'.sql';
print( "Executing '$command'\n" ) if ( logDebugging() ); print("Executing '$command'\n") if logDebugging();
my $output = qx($command); my $output = qx($command);
my $status = $? >> 8; my $status = $? >> 8;
if ( $status || logDebugging() ) { if ( $status || logDebugging() ) {
chomp( $output ); chomp($output);
print( "Output: $output\n" ); print("Output: $output\n");
} }
if ( $status ) { 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 { sub migratePasswords {
print ("Migratings passwords, if any...\n"); print ("Migratings passwords, if any...\n");
my $sql = "select * from Users"; my $sql = 'SELECT * FROM `Users`';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); 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 $res = $sth->execute() or die("Can't execute: ".$sth->errstr());
while( my $user = $sth->fetchrow_hashref() ) { while( my $user = $sth->fetchrow_hashref() ) {
my $scheme = substr($user->{Password}, 0, 1); my $scheme = substr($user->{Password}, 0, 1);
if ($scheme eq "*") { if ($scheme eq '*') {
print ("-->".$user->{Username}. " password will be migrated\n"); print ('-->'.$user->{Username}." password will be migrated\n");
my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8)); my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8));
my $settings = '$2a$10$'.$salt; my $settings = '$2a$10$'.$salt;
my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings); my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings);
my $new_pass_hash = "-ZM-".$pass_hash; my $new_pass_hash = '-ZM-'.$pass_hash;
$sql = "UPDATE Users SET PASSWORD=? WHERE Username=?"; $sql = 'UPDATE Users SET `Password`=? WHERE `Username`=?';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); 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() ); my $res = $sth->execute($new_pass_hash, $user->{Username}) or die("Can't execute: ".$sth->errstr());
} }
} }
} } # end sub migratePasswords
sub migratePaths { sub migratePaths {

View File

@ -76,7 +76,7 @@ bool EventStream::loadInitialEventData(int monitor_id, time_t event_time) {
curr_frame_id = 1; // curr_frame_id is 1-based curr_frame_id = 1; // curr_frame_id is 1-based
if ( event_time >= event_data->start_time ) { if ( event_time >= event_data->start_time ) {
Debug(2, "event time is after event start"); 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 ); //Info( "eft %d > et %d", event_data->frames[i].timestamp, event_time );
if ( event_data->frames[i].timestamp >= event_time ) { if ( event_data->frames[i].timestamp >= event_time ) {
curr_frame_id = i+1; curr_frame_id = i+1;
@ -374,18 +374,20 @@ void EventStream::processCommand(const CmdMsg *msg) {
} }
break; break;
case CMD_SLOWFWD : case CMD_SLOWFWD :
Debug(1, "Got SLOW FWD command");
paused = true; paused = true;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
step = 1; 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; break;
case CMD_SLOWREV : case CMD_SLOWREV :
Debug(1, "Got SLOW REV command");
paused = true; paused = true;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
step = -1; step = -1;
curr_frame_id -= 1; curr_frame_id -= 1;
if ( curr_frame_id < 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; break;
case CMD_FASTREV : case CMD_FASTREV :
Debug(1, "Got FAST REV command"); Debug(1, "Got FAST REV command");
@ -848,20 +850,15 @@ void EventStream::runStream() {
// commands may set send_frame to true // commands may set send_frame to true
while ( checkCommandQueue() && !zm_terminate ) { while ( checkCommandQueue() && !zm_terminate ) {
// The idea is to loop here processing all commands before proceeding. // 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. // 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 ) { if ( now.tv_sec - last_comm_update.tv_sec > 3600 ) {
touch(sock_path_lock); touch(sock_path_lock);
last_comm_update = now; last_comm_update = now;
} }
} else {
Debug(2, "Not checking command queue");
} }
// Get current frame data // Get current frame data
FrameData *frame_data = &event_data->frames[curr_frame_id-1]; FrameData *frame_data = &event_data->frames[curr_frame_id-1];
@ -1017,6 +1014,7 @@ void EventStream::runStream() {
curr_frame_id += step; curr_frame_id += step;
// Detects when we hit end of event and will load the next event or previous event // Detects when we hit end of event and will load the next event or previous event
if ( !paused )
checkEventLoaded(); checkEventLoaded();
} // end while ! zm_terminate } // end while ! zm_terminate
#if HAVE_LIBAVCODEC #if HAVE_LIBAVCODEC

View File

@ -20,9 +20,6 @@
#ifndef ZM_EVENTSTREAM_H #ifndef ZM_EVENTSTREAM_H
#define ZM_EVENTSTREAM_H #define ZM_EVENTSTREAM_H
#include <set>
#include <map>
#include "zm_image.h" #include "zm_image.h"
#include "zm_stream.h" #include "zm_stream.h"
#include "zm_video.h" #include "zm_video.h"

View File

@ -24,7 +24,7 @@ static char* GetPasswordCallback(rfbClient* cl){
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential)); rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential));
if(credentialType != rfbCredentialTypeUser) { if ( credentialType != rfbCredentialTypeUser ) {
return NULL; return NULL;
} }
@ -68,7 +68,7 @@ VncCamera::VncCamera(
mPass(pass) mPass(pass)
{ {
Debug(2, "Host:%s Port: %s User: %s Pass:%s", mHost.c_str(), mPort.c_str(), mUser.c_str(), mPass.c_str()); 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(); Initialise();
} }
@ -102,16 +102,28 @@ void VncCamera::Terminate() {
int VncCamera::PrimeCapture() { int VncCamera::PrimeCapture() {
Info("Priming capture from %s", mHost.c_str()); Info("Priming capture from %s", mHost.c_str());
if(mRfb->si.framebufferWidth != width || mRfb->si.framebufferHeight != height) { if ( mRfb->si.framebufferWidth != width || mRfb->si.framebufferHeight != height ) {
Info("Expected screen resolution does not match with the provided resolution, using scaling"); 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; 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; return 0;
} }
int VncCamera::PreCapture() { int VncCamera::PreCapture() {
Debug(2, "PreCapture");
WaitForMessage(mRfb, 500); WaitForMessage(mRfb, 500);
Debug(2, "After Wait ");
rfbBool res = HandleRFBServerMessage(mRfb); rfbBool res = HandleRFBServerMessage(mRfb);
Debug(2, "After Handle ");
return res == TRUE ? 1 : -1 ; return res == TRUE ? 1 : -1 ;
} }
@ -120,46 +132,39 @@ int VncCamera::Capture(Image &image) {
int srcLineSize[4]; int srcLineSize[4];
int dstLineSize[4]; int dstLineSize[4];
int dstSize; int dstSize;
if(mScale) {
sws = sws_getContext(mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, AV_PIX_FMT_RGBA, if ( mScale ) {
width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); uint8_t* directbuffer;
if(!sws) {
Error("Could not scale image"); /* 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; 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) { mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, 16) < 0) {
sws_freeContext(sws);
Error("Could not allocate source image. Scaling failed"); Error("Could not allocate source image. Scaling failed");
return -1; 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, sws_scale(sws, (const uint8_t* const*)srcbuf, srcLineSize, 0, mRfb->si.framebufferHeight,
dstbuf, dstLineSize); dstbuf, dstLineSize);
} } else {
else{
dstbuf[0] = mVncData.buffer;
}
image.Assign(width, height, colours, subpixelorder, mVncData.buffer, width * height * 4); image.Assign(width, height, colours, subpixelorder, mVncData.buffer, width * height * 4);
}
return 1; return 1;
} }
int VncCamera::PostCapture() { int VncCamera::PostCapture() {
if(mScale) {
av_freep(&srcbuf[0]);
av_freep(&dstbuf[0]);
sws_freeContext(sws);
}
return 0; return 0;
} }
@ -168,6 +173,15 @@ int VncCamera::CaptureAndRecord(Image &image, timeval recording, char* event_dir
} }
int VncCamera::Close() { int VncCamera::Close() {
#if HAVE_LIBSWSCALE
if ( mScale ) {
av_freep(&srcbuf[0]);
av_freep(&dstbuf[0]);
sws_freeContext(sws);
sws = NULL;
}
#endif
rfbClientCleanup(mRfb); rfbClientCleanup(mRfb);
return 0; return 0;
} }

View File

@ -55,7 +55,7 @@ static _AVPIXELFORMAT getFfPixFormatFromV4lPalette(int v4l_version, int palette)
#if ZM_HAS_V4L2 #if ZM_HAS_V4L2
if ( v4l_version == 2 ) { if ( v4l_version == 2 ) {
switch( palette ) { switch ( palette ) {
#if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444) #if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444)
case V4L2_PIX_FMT_RGB444 : case V4L2_PIX_FMT_RGB444 :
pixFormat = AV_PIX_FMT_RGB444; pixFormat = AV_PIX_FMT_RGB444;
@ -745,12 +745,12 @@ void LocalCamera::Initialise() {
Debug(4, Debug(4,
" v4l2_data.fmt.type = %08x\n" " v4l2_data.fmt.type = %08x\n"
" v4l2_data.fmt.fmt.pix.width = %08x\n" " v4l2_data.fmt.fmt.pix.width = %d\n"
" v4l2_data.fmt.fmt.pix.height = %08x\n" " v4l2_data.fmt.fmt.pix.height = %d\n"
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
" v4l2_data.fmt.fmt.pix.field = %08x\n" " v4l2_data.fmt.fmt.pix.field = %08x\n"
" v4l2_data.fmt.fmt.pix.bytesperline = %08x\n" " v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
" v4l2_data.fmt.fmt.pix.sizeimage = %08x\n" " v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n" " v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
" v4l2_data.fmt.fmt.pix.priv = %08x\n" " v4l2_data.fmt.fmt.pix.priv = %08x\n"
, v4l2_data.fmt.type , v4l2_data.fmt.type
@ -788,12 +788,12 @@ void LocalCamera::Initialise() {
/* Note VIDIOC_S_FMT may change width and height. */ /* Note VIDIOC_S_FMT may change width and height. */
Debug(4, Debug(4,
" v4l2_data.fmt.type = %08x\n" " v4l2_data.fmt.type = %08x\n"
" v4l2_data.fmt.fmt.pix.width = %08x\n" " v4l2_data.fmt.fmt.pix.width = %d\n"
" v4l2_data.fmt.fmt.pix.height = %08x\n" " v4l2_data.fmt.fmt.pix.height = %d\n"
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
" v4l2_data.fmt.fmt.pix.field = %08x\n" " v4l2_data.fmt.fmt.pix.field = %08x\n"
" v4l2_data.fmt.fmt.pix.bytesperline = %08x\n" " v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
" v4l2_data.fmt.fmt.pix.sizeimage = %08x\n" " v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n" " v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
" v4l2_data.fmt.fmt.pix.priv = %08x\n" " v4l2_data.fmt.fmt.pix.priv = %08x\n"
, v4l2_data.fmt.type , v4l2_data.fmt.type

View File

@ -80,7 +80,7 @@ fi;
if [ "$DISTROS" == "" ]; then if [ "$DISTROS" == "" ]; then
if [ "$RELEASE" != "" ]; then if [ "$RELEASE" != "" ]; then
DISTROS="xenial,bionic,disco,eoan,trusty" DISTROS="xenial,bionic,disco,eoan,focal,trusty"
else else
DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`; DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
fi; fi;

View File

@ -1 +1 @@
1.35.1 1.35.2

View File

@ -379,6 +379,8 @@ class MonitorsController extends AppController {
$args = ''; $args = '';
if ( $daemon == 'zmc' and $monitor['Type'] == 'Local' ) { if ( $daemon == 'zmc' and $monitor['Type'] == 'Local' ) {
$args = '-d ' . $monitor['Device']; $args = '-d ' . $monitor['Device'];
} else if ( $daemon == 'zmcontrol.pl' ) {
$args = '--id '.$id;
} else { } else {
$args = '-m ' . $id; $args = '-m ' . $id;
} }

View File

@ -497,6 +497,10 @@ class Monitor extends ZM_Object {
if ( !count($options) ) { if ( !count($options) ) {
if ( $command == 'quit' ) { if ( $command == 'quit' ) {
$options['command'] = 'quit'; $options['command'] = 'quit';
} else if ( $command == 'start' ) {
$options['command'] = 'start';
} else if ( $command == 'stop' ) {
$options['command'] = 'stop';
} else { } else {
Warning("No commands to send to zmcontrol from $command"); Warning("No commands to send to zmcontrol from $command");
return false; return false;
@ -531,7 +535,7 @@ class Monitor extends ZM_Object {
} else if ( $this->ServerId() ) { } else if ( $this->ServerId() ) {
$Server = $this->Server(); $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_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) { if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash( ZM_AUTH_HASH_IPS ); $url .= '?auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
@ -547,12 +551,12 @@ class Monitor extends ZM_Object {
$context = stream_context_create(); $context = stream_context_create();
try { try {
$result = file_get_contents($url, false, $context); $result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ if ( $result === FALSE ) { /* Handle error */
Error("Error restarting zma using $url"); Error("Error sending command using $url");
return false; return false;
} }
} catch ( Exception $e ) { } catch ( Exception $e ) {
Error("Except $e thrown trying to restart zma"); Error("Exception $e thrown trying to send command to $url");
return false; return false;
} }
} else { } else {

View File

@ -21,38 +21,27 @@
// Group edit actions // Group edit actions
# Should probably verify that each monitor id is a valid monitor, that we have access to. # 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 # 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'); ZM\Warning('Need group edit permissions to edit groups');
return; return;
} }
if ( $action == 'Save' ) { if ( $action == 'Save' ) {
$monitors = empty($_POST['newGroup']['MonitorIds']) ? '' : implode(',', $_POST['newGroup']['MonitorIds']);
$group_id = null; $group_id = null;
if ( !empty($_POST['gid']) ) { if ( !empty($_POST['gid']) )
$group_id = $_POST['gid']; $group_id = $_POST['gid'];
dbQuery( $group = new ZM\Group($group_id);
'UPDATE Groups SET Name=?, ParentId=? WHERE Id=?', $group->save(
array( array(
$_POST['newGroup']['Name'], 'Name'=> $_POST['newGroup']['Name'],
( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), 'ParentId'=>( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ),
$group_id,
) )
); );
dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($group_id)); dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id));
} else { $group_id = $group->Id();
dbQuery(
'INSERT INTO Groups (Name,ParentId) VALUES (?,?)',
array(
$_POST['newGroup']['Name'],
( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ),
)
);
$group_id = dbInsertId();
}
if ( $group_id ) { if ( $group_id ) {
foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) { 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'; $view = 'none';

View File

@ -92,6 +92,9 @@ if ( $action == 'monitor' ) {
if ( $monitor->Type() != 'WebSite' ) { if ( $monitor->Type() != 'WebSite' ) {
$monitor->zmaControl('stop'); $monitor->zmaControl('stop');
$monitor->zmcControl('stop'); $monitor->zmcControl('stop');
if ( $monitor->Controllable() ) {
$monitor->sendControlCommand('stop');
}
} }
# These are used in updating zones # These are used in updating zones
@ -264,8 +267,7 @@ if ( $action == 'monitor' ) {
$monitor->zmaControl('start'); $monitor->zmaControl('start');
if ( $monitor->Controllable() ) { if ( $monitor->Controllable() ) {
require_once('includes/control_functions.php'); $monitor->sendControlCommand('start');
$monitor->sendControlCommand('quit');
} }
} }
// really should thump zmwatch and maybe zmtrigger too. // really should thump zmwatch and maybe zmtrigger too.

View File

@ -36,7 +36,7 @@ if ( isset($_REQUEST['object']) ) {
} }
$Layout->Positions($_REQUEST['Positions']); $Layout->Positions($_REQUEST['Positions']);
$Layout->save(); $Layout->save();
session_start(); zm_session_start();
$_SESSION['zmMontageLayout'] = $Layout->Id(); $_SESSION['zmMontageLayout'] = $Layout->Id();
setcookie('zmMontageLayout', $Layout->Id(), 1); setcookie('zmMontageLayout', $Layout->Id(), 1);
session_write_close(); session_write_close();

View File

@ -210,7 +210,6 @@ function Monitor(monitorData) {
* @param {*} element - the event data passed by onchange callback * @param {*} element - the event data passed by onchange callback
*/ */
function selectLayout(element) { function selectLayout(element) {
console.log(element);
layout = $j(element).val(); layout = $j(element).val();
if ( layout_id = parseInt(layout) ) { if ( layout_id = parseInt(layout) ) {
@ -221,8 +220,8 @@ function selectLayout(element) {
// Need to clear the current positioning, and apply the new // Need to clear the current positioning, and apply the new
monitor_frame = $j('#monitorFrame'+monitor.id); monitor_frame = $j('#monitorFrame'+monitor.id);
if ( ! monitor_frame ) { if ( !monitor_frame ) {
console.log("Error finding frame for " + monitor.id); console.log('Error finding frame for ' + monitor.id);
continue; continue;
} }
@ -262,6 +261,10 @@ function selectLayout(element) {
if ( streamImg.nodeName == 'IMG' ) { if ( streamImg.nodeName == 'IMG' ) {
var src = streamImg.src; var src = streamImg.src;
src = src.replace(/width=[\.\d]+/i, 'width=0' ); 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 ) { if ( src != streamImg.src ) {
streamImg.src = ''; streamImg.src = '';
streamImg.src = src; streamImg.src = src;

View File

@ -730,12 +730,12 @@ switch ( $tab ) {
continue; continue;
if ( $optCount && ($optCount%$breakCount == 0) ) if ( $optCount && ($optCount%$breakCount == 0) )
echo '</br>'; echo '</br>';
echo '<input type="checkbox" name="newMonitor[Triggers][]" value="'. $optTrigger. '"'. echo '<input type="checkbox" name="newMonitor[Triggers][]" value="'.$optTrigger.'"'.
(( ('' !== $monitor->Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"':''). '/> '. $optTrigger; (( ('' !== $monitor->Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"' : ''). '/> '. $optTrigger;
$optCount ++; $optCount ++;
} # end foreach trigger option } # end foreach trigger option
if ( !$optCount ) { if ( !$optCount ) {
echo '<em>'. translate('NoneAvailable') .'</em>'; echo '<em>'.translate('NoneAvailable').'</em>';
} }
?> ?>
</td></tr> </td></tr>

View File

@ -66,17 +66,19 @@ foreach ( $layouts as $l ) {
} }
} }
foreach ( $layouts as $l ) { foreach ( $layouts as $l ) {
if ( $l->Name() != "Freeform" ) if ( $l->Name() != 'Freeform' )
$layoutsById[$l->Id()] = $l; $layoutsById[$l->Id()] = $l;
} }
session_start(); zm_session_start();
$layout_id = ''; $layout_id = '';
if ( isset($_COOKIE['zmMontageLayout']) ) { if ( isset($_COOKIE['zmMontageLayout']) ) {
$layout_id = $_SESSION['zmMontageLayout'] = $_COOKIE['zmMontageLayout']; $layout_id = $_SESSION['zmMontageLayout'] = $_COOKIE['zmMontageLayout'];
#} elseif ( isset($_SESSION['zmMontageLayout']) ) { ZM\Logger::Debug("Using layout $layout_id");
#$layout_id = $_SESSION['zmMontageLayout']; } elseif ( isset($_SESSION['zmMontageLayout']) ) {
$layout_id = $_SESSION['zmMontageLayout'];
ZM\Logger::Debug("Using layout $layout_id from session");
} }
$options = array(); $options = array();
@ -85,6 +87,8 @@ $Positions = '';
if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) ) { if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) ) {
$Layout = $layoutsById[$layout_id]; $Layout = $layoutsById[$layout_id];
$Positions = json_decode($Layout->Positions(), true); $Positions = json_decode($Layout->Positions(), true);
} else {
ZM\Logger::Debug("Layout not found");
} }
if ( $Layout and ( $Layout->Name() != 'Freeform' ) ) { if ( $Layout and ( $Layout->Name() != 'Freeform' ) ) {
// Use layout instead of other options // Use layout instead of other options