diff --git a/.travis.yml b/.travis.yml index 183d22e57..3dbe1e066 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,4 +45,4 @@ script: - mysql -uzmuser -pzmpass < db/zm_create.sql - mysql -uzmuser -pzmpass zm < db/test.monitor.sql - sudo zmpkg.pl start - - sudo zmfilter.pl -f purgewhenfull + - sudo zmfilter.pl --filter purgewhenfull diff --git a/distros/debian/postinst b/distros/debian/postinst index 8bb4d23eb..39e3dfc32 100644 --- a/distros/debian/postinst +++ b/distros/debian/postinst @@ -10,7 +10,7 @@ if [ "$1" = "configure" ]; then chown www-data:root /var/log/zm chown www-data:www-data /var/lib/zm if [ -z "$2" ]; then - chown www-data:www-data -R /var/cache/zoneminder + chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* fi # Do this every time the package is installed or upgraded diff --git a/distros/ubuntu1204/zoneminder.postinst b/distros/ubuntu1204/zoneminder.postinst index 1bfd41d42..7c01cdde4 100644 --- a/distros/ubuntu1204/zoneminder.postinst +++ b/distros/ubuntu1204/zoneminder.postinst @@ -10,7 +10,7 @@ if [ "$1" = "configure" ]; then chown www-data:root /var/log/zm chown www-data:www-data /var/lib/zm if [ -z "$2" ]; then - chown www-data:www-data -R /var/cache/zoneminder + chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* fi # Do this every time the package is installed or upgraded diff --git a/distros/ubuntu1504/control b/distros/ubuntu1504/control index c1b7d958f..0b32a37ac 100644 --- a/distros/ubuntu1504/control +++ b/distros/ubuntu1504/control @@ -6,6 +6,7 @@ Uploaders: Vagrant Cascadian Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apache2-dev, dh-linktree ,cmake ,libavcodec-ffmpeg-dev, libavformat-ffmpeg-dev, libswscale-ffmpeg-dev, libavutil-ffmpeg-dev, libavdevice-ffmpeg-dev + ,libx264-dev, libmp4v2-dev, ,libbz2-dev ,libgcrypt-dev ,libcurl4-gnutls-dev @@ -34,10 +35,8 @@ Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,javascript-common ,libav-tools - ,libdate-manip-perl + ,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl ,libdbd-mysql-perl - ,libmime-lite-perl - ,libmime-tools-perl ,libphp-serialization-perl ,libmodule-load-conditional-perl ,libnet-sftp-foreign-perl @@ -57,12 +56,12 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,libsys-cpu-perl, libsys-meminfo-perl ,mysql-client | virtual-mysql-client ,perl-modules - ,php5-mysql, php5-gd + ,php5-mysql | php-mysql, php5-gd | php-gd ,policykit-1 ,rsyslog | system-log-daemon ,zip Recommends: ${misc:Recommends} - ,libapache2-mod-php5 | php5-fpm + ,libapache2-mod-php5 | libapache2-mod-php7 | php5-fpm ,mysql-server | virtual-mysql-server ,zoneminder-doc (>= ${source:Version}) Suggests: fcgiwrap, logrotate diff --git a/distros/ubuntu1504/zoneminder.postinst b/distros/ubuntu1504/zoneminder.postinst index c45474e1d..64699d1ca 100644 --- a/distros/ubuntu1504/zoneminder.postinst +++ b/distros/ubuntu1504/zoneminder.postinst @@ -10,7 +10,7 @@ if [ "$1" = "configure" ]; then chown www-data:root /var/log/zm chown www-data:www-data /var/lib/zm if [ -z "$2" ]; then - chown www-data:www-data -R /var/cache/zoneminder + chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* fi # Do this every time the package is installed or upgraded diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 18306e52f..fc4143d8a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -3825,6 +3825,41 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s readonly => 1, category => "dynamic", }, + { + name => "ZM_SSMTP_MAIL", + default => "no", + description => qqq(" + Use a SSMTP mail server if available. + NEW_MAIL_MODULES must be enabled + "), + requires => [ + { name => "ZM_OPT_EMAIL", value => "yes" }, + { name => "ZM_OPT_MESSAGE", value => "yes" }, + { name => "ZM_NEW_MAIL_MODULES", value => "yes" } + ], + help => qqq(" + SSMTP is a lightweight and efficient method to send email. + The SSMTP application is not installed by default. + NEW_MAIL_MODULES must also be enabled. + Please visit: http://www.zoneminder.com/wiki/index.php/How_to_get_ssmtp_working_with_Zoneminder + for setup and configuration help. + "), + type => $types{boolean}, + category => "mail", + }, + { + name => "ZM_SSMTP_PATH", + default => "", + description => "SSMTP executable path", + requires => [{ name => "ZM_SSMTP_MAIL", value => "yes" }], + help => qqq(" + Recommend setting the path to the SSMTP application. + If path is not defined. Zoneminder will try to determine + the path via shell command. Example path: /usr/sbin/ssmtp. + "), + type => $types{string}, + category => "mail", + }, ); our %options_hash = map { ( $_->{name}, $_ ) } @options; diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index c95f65441..a8cebde89 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -155,10 +155,12 @@ MAIN: while( $loop ) { Fatal("ZM_AUDIT_MIN_AGE is not set in config."); } + my %Monitors; my $db_monitors; - my $monitorSelectSql = "select Id from Monitors order by Id"; + my $monitorSelectSql = "select * from Monitors order by Id"; my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() ); + my $eventSelectSql = "SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age FROM Events WHERE MonitorId = ? ORDER BY Id"; my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) @@ -169,6 +171,8 @@ MAIN: while( $loop ) { or Fatal( "Can't execute: ".$monitorSelectSth->errstr() ); while( my $monitor = $monitorSelectSth->fetchrow_hashref() ) { + $Monitors{$$monitor{Id}} = $monitor; + Debug( "Found database monitor '$monitor->{Id}'" ); my $db_events = $db_monitors->{$monitor->{Id}} = {}; my $res = $eventSelectSth->execute( $monitor->{Id} ) @@ -467,20 +471,30 @@ MAIN: while( $loop ) { # New audit to close any events that were left open for longer than MIN_AGE seconds my $selectUnclosedEventsSql = - "SELECT E.Id, - max(F.TimeStamp) as EndTime, - unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, - max(F.FrameId) as Frames, + #"SELECT E.Id, ANY_VALUE(E.MonitorId), +# + #max(F.TimeStamp) as EndTime, + #unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, + #max(F.FrameId) as Frames, + #count(if(F.Score>0,1,NULL)) as AlarmFrames, + #sum(F.Score) as TotScore, + #max(F.Score) as MaxScore + #FROM Events as E + #INNER JOIN Frames as F on E.Id = F.EventId + #WHERE isnull(E.Frames) or isnull(E.EndTime) + #GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)" + #; + "SELECT *, unix_timestamp(StartTime) AS TimeStamp FROM Events WHERE EndTime IS NULL AND StartTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)"; + + my $selectFrameDataSql = "SELECT max(TimeStamp) as EndTime, unix_timestamp(max(TimeStamp)) AS EndTimeStamp, max(FrameId) as Frames, count(if(F.Score>0,1,NULL)) as AlarmFrames, sum(F.Score) as TotScore, - max(F.Score) as MaxScore, - M.EventPrefix as Prefix - FROM Events as E - LEFT JOIN Monitors as M on E.MonitorId = M.Id - INNER JOIN Frames as F on E.Id = F.EventId - WHERE isnull(E.Frames) or isnull(E.EndTime) - GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)" - ; + max(F.Score) as MaxScore + FROM Frames WHERE EventId=?"; + my $selectFrameDataSth = $dbh->prepare_cached($selectFrameDataSql) + or Fatal( "Can't prepare '$selectFrameDataSql': ".$dbh->errstr() ); + + my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() ); my $updateUnclosedEventsSql = @@ -505,26 +519,32 @@ MAIN: while( $loop ) { aud_print( "Found open event '$event->{Id}'" ); if ( confirm( 'close', 'closing' ) ) { - $res = $updateUnclosedEventsSth->execute - ( - sprintf("%s%d%s", - $event->{Prefix}, - $event->{Id}, - RECOVER_TAG - ), - $event->{EndTime}, - $event->{Length}, - $event->{Frames}, - $event->{AlarmFrames}, - $event->{TotScore}, - $event->{AlarmFrames} - ? int($event->{TotScore} / $event->{AlarmFrames}) - : 0 - , - $event->{MaxScore}, - RECOVER_TEXT, - $event->{Id} - ) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() ); + $res = $selectFrameDataSth->execute( $event->{Id} ); + my $frame = $selectFrameDataSth->fetchrow_hashref(); + if ( $frame ) { + $res = $updateUnclosedEventsSth->execute + ( + sprintf("%s%d%s", + $Monitors{$event->{MonitorId}}->{EventPrefix}, + $event->{Id}, + RECOVER_TAG + ), + $frame->{EndTime}, + $frame->{EndTimeStamp} - $event->{TimeStamp}, + $frame->{Frames}, + $frame->{AlarmFrames}, + $frame->{TotScore}, + $frame->{AlarmFrames} + ? int($frame->{TotScore} / $frame->{AlarmFrames}) + : 0 + , + $frame->{MaxScore}, + RECOVER_TEXT, + $event->{Id} + ) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() ); + } else { + Error("SHOULD DELETE"); + } # end if has frame data } } diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index b068b9a49..36d5e922a 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -862,7 +862,7 @@ sub killAll my $killall; if ( '@HOST_OS@' eq 'BSD' ) { - $killall = 'killall -'; + $killall = 'killall -q -'; } elsif ( '@HOST_OS@' eq 'solaris' ) { $killall = 'pkill -'; } else { diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 511754a33..7c8244f83 100755 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -779,9 +779,31 @@ sub sendEmail Disposition => "attachment" ); } + if ( $Config{ZM_SSMTP_MAIL} ){ + + my $ssmtp_location = $Config{ZM_SSMTP_PATH}; + + if( ! $ssmtp_location ){ + + $ssmtp_location = qx('which ssmtp'); + + if ( logDebugging() ) + { + Debug( "which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message\n" ); + } + + } + + $mail->send( 'sendmail', $ssmtp_location, $Config{ZM_EMAIL_ADDRESS} ); + + }else{ + + MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); + $mail->send(); + } ### Send the Message - MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); - $mail->send(); + #MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); + #$mail->send(); } else { diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 5a7454a7b..1a5c65840 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -117,7 +117,8 @@ void zmLoadConfig() Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() ); std::string sql = stringtf("SELECT Id FROM Servers WHERE Name='%s'", staticConfig.SERVER_NAME.c_str() ); - if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { + zmDbRow dbrow; + if ( dbrow.fetch( sql.c_str() ) ) { staticConfig.SERVER_ID = atoi(dbrow[0]); } else { Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() ); @@ -128,7 +129,8 @@ void zmLoadConfig() Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID ); std::string sql = stringtf("SELECT Name FROM Servers WHERE Id='%d'", staticConfig.SERVER_ID ); - if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { + zmDbRow dbrow; + if ( dbrow.fetch( sql.c_str() ) ) { staticConfig.SERVER_NAME = std::string(dbrow[0]); } else { Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID ); diff --git a/src/zm_db.cpp b/src/zm_db.cpp index a342ca14b..7d418abf9 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -95,19 +95,38 @@ MYSQL_RES * zmDbFetch( const char * query ) { return result; } // end MYSQL_RES * zmDbFetch( const char * query ); -MYSQL_ROW zmDbFetchOne( const char *query ) { - MYSQL_RES *result = zmDbFetch( query ); - int n_rows = mysql_num_rows( result ); - if ( n_rows != 1 ) { - Error( "Bogus number of lines return from query, %d returned for query %s.", n_rows, query ); - return NULL; - } - - MYSQL_ROW dbrow = mysql_fetch_row( result ); - mysql_free_result( result ); - if ( ! dbrow ) { - Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) ); - return NULL; - } - return dbrow; +zmDbRow *zmDbFetchOne( const char *query ) { + zmDbRow *row = new zmDbRow(); + if ( row->fetch( query ) ) { + return row; + } + delete row; + return NULL; +} + +MYSQL_RES *zmDbRow::fetch( const char *query ) { + result_set = zmDbFetch( query ); + if ( ! result_set ) return result_set; + + int n_rows = mysql_num_rows( result_set ); + if ( n_rows != 1 ) { + Error( "Bogus number of lines return from query, %d returned for query %s.", n_rows, query ); + mysql_free_result( result_set ); + result_set = NULL; + return result_set; + } + + row = mysql_fetch_row( result_set ); + if ( ! row ) { + mysql_free_result( result_set ); + result_set = NULL; + Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) ); + } else { + Debug(3, "Succes"); + } + return result_set; +} +zmDbRow::~zmDbRow() { + if ( result_set ) + mysql_free_result( result_set ); } diff --git a/src/zm_db.h b/src/zm_db.h index 6ec1b5e4e..50ae2974f 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -22,6 +22,21 @@ #include +class zmDbRow { + private: + MYSQL_RES *result_set; + MYSQL_ROW row; + public: + zmDbRow() { result_set = NULL; row = NULL; }; + MYSQL_RES *fetch( const char *query ); + zmDbRow( MYSQL_RES *, MYSQL_ROW *row ); + ~zmDbRow(); + + char *operator[](unsigned int index) const { + return row[index]; + } +}; + #ifdef __cplusplus extern "C" { #endif @@ -33,7 +48,7 @@ void zmDbConnect(); void zmDbClose(); MYSQL_RES * zmDbFetch( const char *query ); -MYSQL_ROW zmDbFetchOne( const char *query ); +zmDbRow *zmDbFetchOne( const char *query ); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 281009703..9af56c971 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -167,12 +167,21 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint #endif /* Check the buffer sizes */ - size_t insize = avpicture_get_size(in_pf, width, height); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + size_t insize = av_image_get_buffer_size(in_pf, width, height,1); +#else + size_t insize = avpicture_get_size(in_pf, width, height); +#endif if(insize != in_buffer_size) { Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size); return -4; } - size_t outsize = avpicture_get_size(out_pf, width, height); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + size_t outsize = av_image_get_buffer_size(out_pf, width, height,1); +#else + size_t outsize = avpicture_get_size(out_pf, width, height); +#endif + if(outsize < out_buffer_size) { Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size); return -5; @@ -186,13 +195,29 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint } /* Fill in the buffers */ - if(!avpicture_fill( (AVPicture*)input_avframe, (uint8_t*)in_buffer, in_pf, width, height ) ) { - Error("Failed filling input frame with input buffer"); - return -7; +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + if(av_image_fill_arrays(input_avframe->data, input_avframe->linesize, + (uint8_t*)in_buffer, in_pf, width, height, 1) <= 0) + { +#else + if(avpicture_fill( (AVPicture*)input_avframe, (uint8_t*)in_buffer, + in_pf, width, height ) <= 0) + { +#endif + Error("Failed filling input frame with input buffer"); + return -7; } - if(!avpicture_fill( (AVPicture*)output_avframe, out_buffer, out_pf, width, height ) ) { - Error("Failed filling output frame with output buffer"); - return -8; +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + if(av_image_fill_arrays(output_avframe->data, output_avframe->linesize, + out_buffer, out_pf, width, height, 1) <= 0) + { +#else + if(avpicture_fill( (AVPicture*)output_avframe, out_buffer, + out_pf, width, height ) <= 0) + { +#endif + Error("Failed filling output frame with output buffer"); + return -8; } /* Do the conversion */ diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index ccd39ec40..ca74af2f8 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -48,6 +48,12 @@ extern "C" { #else #include #endif + +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) +#include +#else +#include +#endif #elif HAVE_FFMPEG_AVUTIL_H #include #include diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index a8a72db09..88a2a43c5 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -193,7 +193,13 @@ int FfmpegCamera::Capture( Image &image ) if ( frameComplete ) { Debug( 4, "Got frame %d", frameCount ); - avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(mFrame->data, mFrame->linesize, + directbuffer, imagePixFormat, width, height, 1); +#else + avpicture_fill( (AVPicture *)mFrame, directbuffer, + imagePixFormat, width, height); +#endif #if HAVE_LIBSWSCALE if(mConvertContext == NULL) { @@ -395,7 +401,12 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Allocated frames" ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int pSize = av_image_get_buffer_size( imagePixFormat, width, height,1 ); +#else int pSize = avpicture_get_size( imagePixFormat, width, height ); +#endif + if( (unsigned int)pSize != imagesize) { Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize); } @@ -583,8 +594,8 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi //Keep the last keyframe so we can establish immediate video if(packet.flags & AV_PKT_FLAG_KEY) { - Debug(4, "Have keyframe"); - av_copy_packet(&lastKeyframePkt, &packet); + //Debug(4, "Have keyframe"); + //av_copy_packet(&lastKeyframePkt, &packet); //TODO I think we need to store the key frame location for seeking as part of the event } diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 1a22f4c8c..ca5f79472 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -644,7 +644,11 @@ LocalCamera::LocalCamera( if ( !tmpPicture ) Fatal( "Could not allocate temporary picture" ); - int pSize = avpicture_get_size( imagePixFormat, width, height ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int pSize = av_image_get_buffer_size( imagePixFormat, width, height,1 ); +#else + int pSize = avpicture_get_size( imagePixFormat, width, height ); +#endif if( (unsigned int)pSize != imagesize) { Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize); } @@ -877,7 +881,18 @@ void LocalCamera::Initialise() #endif if ( !capturePictures[i] ) Fatal( "Could not allocate picture" ); - avpicture_fill( (AVPicture *)capturePictures[i], (uint8_t*)v4l2_data.buffers[i].start, capturePixFormat, v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(capturePictures[i]->data, + capturePictures[i]->linesize, + (uint8_t*)v4l2_data.buffers[i].start,capturePixFormat, + v4l2_data.fmt.fmt.pix.width, + v4l2_data.fmt.fmt.pix.height, 1); +#else + avpicture_fill( (AVPicture *)capturePictures[i], + (uint8_t*)v4l2_data.buffers[i].start, capturePixFormat, + v4l2_data.fmt.fmt.pix.width, + v4l2_data.fmt.fmt.pix.height ); +#endif #endif // HAVE_LIBSWSCALE } @@ -1035,7 +1050,16 @@ void LocalCamera::Initialise() #endif if ( !capturePictures[i] ) Fatal( "Could not allocate picture" ); - avpicture_fill( (AVPicture *)capturePictures[i], (unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i], capturePixFormat, width, height ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(capturePictures[i]->data, + capturePictures[i]->linesize, + (unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i], + capturePixFormat, width, height, 1); +#else + avpicture_fill( (AVPicture *)capturePictures[i], + (unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i], + capturePixFormat, width, height ); +#endif } #endif // HAVE_LIBSWSCALE @@ -2131,7 +2155,14 @@ int LocalCamera::Capture( Image &image ) Debug( 9, "Calling sws_scale to perform the conversion" ); /* Use swscale to convert the image directly into the shared memory */ - avpicture_fill( (AVPicture *)tmpPicture, directbuffer, imagePixFormat, width, height ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(tmpPicture->data, + tmpPicture->linesize, directbuffer, + imagePixFormat, width, height, 1); +#else + avpicture_fill( (AVPicture *)tmpPicture, directbuffer, + imagePixFormat, width, height ); +#endif sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize ); } #endif diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index b747934d2..7c0225e9f 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -286,8 +286,8 @@ Monitor::Monitor( storage_id( p_storage_id ), function( (Function)p_function ), enabled( p_enabled ), - width( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Height():p_camera->Width() ), - height( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Width():p_camera->Height() ), + width( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Height():p_camera->Width() ), + height( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Width():p_camera->Height() ), orientation( (Orientation)p_orientation ), deinterlacing( p_deinterlacing ), savejpegspref( p_savejpegs ), @@ -1119,8 +1119,8 @@ void Monitor::DumpZoneImage( const char *zone_string ) { Debug(3, "Trying to load from event"); // Grab the most revent event image std::string sql = stringtf( "SELECT MAX(Id) FROM Events WHERE MonitorId=%d AND Frames > 0", id ); - MYSQL_ROW eventid_row = zmDbFetchOne(sql.c_str() ); - if ( eventid_row ) { + zmDbRow eventid_row; + if ( eventid_row.fetch( sql.c_str() ) ) { int event_id = atoi( eventid_row[0] ); Debug( 3, "Got event %d", event_id ); @@ -2182,9 +2182,6 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose col++; bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - int extras = (deinterlacing>>24)&0xff; Camera *camera = new LocalCamera( @@ -2195,8 +2192,8 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose v4l_multi_buffer, v4l_captures_per_frame, method, - cam_width, - cam_height, + width, + height, colours, palette, brightness, @@ -2349,9 +2346,6 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c int track_motion = atoi(dbrow[col]); col++; bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - Camera *camera = 0; if ( protocol == "http" ) { camera = new RemoteCameraHttp( @@ -2360,8 +2354,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c host, // Host port, // Port path, // Path - cam_width, - cam_height, + width, + height, colours, brightness, contrast, @@ -2379,8 +2373,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c host, // Host port, // Port path, // Path - cam_width, - cam_height, + width, + height, rtsp_describe, colours, brightness, @@ -2531,14 +2525,11 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu int track_motion = atoi(dbrow[col]); col++; bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - Camera *camera = new FileCamera( id, path, // File - cam_width, - cam_height, + width, + height, colours, brightness, contrast, @@ -2688,16 +2679,13 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose int track_motion = atoi(dbrow[col]); col++; bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - Camera *camera = new FfmpegCamera( id, path, // File method, options, - cam_width, - cam_height, + width, + height, colours, brightness, contrast, @@ -2770,8 +2758,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { std::string sql = stringtf( "select Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id ); - MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ); - if ( ! dbrow ) { + zmDbRow dbrow; + if ( ! dbrow.fetch( sql.c_str() ) ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); } @@ -2869,9 +2857,6 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { col++; bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - int extras = (deinterlacing>>24)&0xff; Camera *camera = 0; @@ -2885,8 +2870,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { v4l_multi_buffer, v4l_captures_per_frame, method, - cam_width, - cam_height, + width, + height, colours, palette, brightness, @@ -2908,8 +2893,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { host.c_str(), port.c_str(), path.c_str(), - cam_width, - cam_height, + width, + height, colours, brightness, contrast, @@ -2926,8 +2911,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { host.c_str(), port.c_str(), path.c_str(), - cam_width, - cam_height, + width, + height, rtsp_describe, colours, brightness, @@ -2947,8 +2932,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { camera = new FileCamera( id, path.c_str(), - cam_width, - cam_height, + width, + height, colours, brightness, contrast, @@ -2964,8 +2949,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { path.c_str(), method, options, - cam_width, - cam_height, + width, + height, colours, brightness, contrast, @@ -2984,8 +2969,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { path.c_str(), method, options, - cam_width, - cam_height, + width, + height, colours, brightness, contrast, @@ -3004,8 +2989,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { path.c_str(), user.c_str(), pass.c_str(), - cam_width, - cam_height, + width, + height, colours, brightness, contrast, diff --git a/src/zm_monitor.h b/src/zm_monitor.h index e00490d7f..70f77ca4c 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -417,8 +417,8 @@ public: return( embed_exif ); } - unsigned int Width() const { return( width ); } - unsigned int Height() const { return( height ); } + unsigned int Width() const { return width; } + unsigned int Height() const { return height; } unsigned int Colours() const { return( camera->Colours() ); } unsigned int SubpixelOrder() const { return( camera->SubpixelOrder() ); } diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index 01f9006b8..1cdf73057 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -333,7 +333,13 @@ void VideoStream::OpenStream( ) Panic( "Could not allocate opicture" ); } +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int size = av_image_get_buffer_size( c->pix_fmt, c->width, + c->height, 1 ); +#else int size = avpicture_get_size( c->pix_fmt, c->width, c->height ); +#endif + uint8_t *opicture_buf = (uint8_t *)av_malloc( size ); if ( !opicture_buf ) { @@ -344,7 +350,13 @@ void VideoStream::OpenStream( ) #endif Panic( "Could not allocate opicture_buf" ); } - avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, c->width, c->height ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(opicture->data, opicture->linesize, + opicture_buf, c->pix_fmt, c->width, c->height, 1); +#else + avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, + c->width, c->height ); +#endif /* if the output format is not identical to the input format, then a temporary picture is needed too. It is then converted to the required @@ -361,7 +373,12 @@ void VideoStream::OpenStream( ) { Panic( "Could not allocate tmp_opicture" ); } +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int size = av_image_get_buffer_size( pf, c->width, + c->height,1 ); +#else int size = avpicture_get_size( pf, c->width, c->height ); +#endif uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size ); if ( !tmp_opicture_buf ) { @@ -372,7 +389,14 @@ void VideoStream::OpenStream( ) #endif Panic( "Could not allocate tmp_opicture_buf" ); } - avpicture_fill( (AVPicture *)tmp_opicture, tmp_opicture_buf, pf, c->width, c->height ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(tmp_opicture->data, + tmp_opicture->linesize, tmp_opicture_buf, pf, + c->width, c->height, 1); +#else + avpicture_fill( (AVPicture *)tmp_opicture, + tmp_opicture_buf, pf, c->width, c->height ); +#endif } } @@ -678,14 +702,14 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, #endif if ( got_packet ) { - if ( c->coded_frame->key_frame ) - { -#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) - pkt->flags |= AV_PKT_FLAG_KEY; -#else - pkt->flags |= PKT_FLAG_KEY; -#endif - } +// if ( c->coded_frame->key_frame ) +// { +//#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) +// pkt->flags |= AV_PKT_FLAG_KEY; +//#else +// pkt->flags |= PKT_FLAG_KEY; +//#endif +// } if ( pkt->pts != (int64_t)AV_NOPTS_VALUE ) { diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 418cea6f8..5256b1de2 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -238,13 +238,18 @@ int RemoteCameraRtsp::PrimeCapture() mFrame = avcodec_alloc_frame(); #endif - if(mRawFrame == NULL || mFrame == NULL) - Fatal( "Unable to allocate frame(s)"); - + if(mRawFrame == NULL || mFrame == NULL) + Fatal( "Unable to allocate frame(s)"); + +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int pSize = av_image_get_buffer_size( imagePixFormat, width, height, 1 ); +#else int pSize = avpicture_get_size( imagePixFormat, width, height ); - if( (unsigned int)pSize != imagesize) { - Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize); - } +#endif + + if( (unsigned int)pSize != imagesize) { + Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize); + } /* #if HAVE_LIBSWSCALE if(!sws_isSupportedInput(mCodecContext->pix_fmt)) { @@ -299,24 +304,6 @@ int RemoteCameraRtsp::Capture( Image &image ) { if ( !buffer.size() ) return( -1 ); -int avResult = av_read_frame( mFormatContext, &packet ); - if ( avResult < 0 ) { - char errbuf[AV_ERROR_MAX_STRING_SIZE]; - av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE); - if ( - // Check if EOF. - (avResult == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) || - // Check for Connection failure. - (avResult == -110) - ) { - Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf); - //ReopenFfmpeg(); - } - - Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf ); - return( -1 ); - } - if(mCodecContext->codec_id == AV_CODEC_ID_H264) { // SPS and PPS frames should be saved and appended to IDR frames int nalType = (buffer.head()[3] & 0x1f); @@ -339,6 +326,8 @@ int avResult = av_read_frame( mFormatContext, &packet ); buffer += lastSps; buffer += lastPps; } + } else { + Debug(3, "Not an h264 packet"); } av_init_packet( &packet ); @@ -498,9 +487,15 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even Debug( 3, "Got frame %d", frameCount ); - avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height ); +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(mFrame->data, mFrame->linesize, + directbuffer, imagePixFormat, width, height, 1); +#else + avpicture_fill( (AVPicture *)mFrame, directbuffer, + imagePixFormat, width, height); +#endif - //Video recording + //Video recording if ( recording && !wasRecording ) { //Instantiate the video storage module diff --git a/src/zm_storage.cpp b/src/zm_storage.cpp index 14a6cfc01..ff2bce5a9 100644 --- a/src/zm_storage.cpp +++ b/src/zm_storage.cpp @@ -50,8 +50,8 @@ Storage::Storage( unsigned int p_id ) { char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "SELECT Id, Name, Path from Storage WHERE Id=%d", p_id ); Debug(1,"Loading Storage for %d using %s", p_id, sql ); - MYSQL_ROW dbrow = zmDbFetchOne( sql ); - if ( ! dbrow ) { + zmDbRow dbrow; + if ( ! dbrow.fetch( sql ) ) { Error( "Unable to load storage area for id %d: %s", p_id, mysql_error( &dbconn ) ); } else { unsigned int index = 0; diff --git a/web/includes/Frame.php b/web/includes/Frame.php new file mode 100644 index 000000000..b7add3b0e --- /dev/null +++ b/web/includes/Frame.php @@ -0,0 +1,76 @@ + $v) { + $this->{$k} = $v; + } + } else { + Error("No row for Frame " . $IdOrRow ); + } + } // end function __construct + public function Storage() { + return $this->Event()->Storage(); + } + public function Event() { + return new Event( $this->{'EventId'} ); + } + public function __call( $fn, array $args){ + if(isset($this->{$fn})){ + return $this->{$fn}; +#array_unshift($args, $this); +#call_user_func_array( $this->{$fn}, $args); + } + } + + public function Path() { + $Storage = $this->Storage(); + return $Storage->Path().'/'.$this->Relative_Path(); + } + public function Relative_Path() { + $event_path = ""; + + if ( ZM_USE_DEEP_STORAGE ) + { + $event_path = + $this->{'MonitorId'} + .'/'.strftime( "%y/%m/%d/%H/%M/%S", + $this->Time() + ) + ; + } + else + { + $event_path = + $this->{'MonitorId'} + .'/'.$this->{'Id'} + ; + } + + return( $event_path ); + + } + + public function getImageSrc( ) { + return ZM_BASE_URL.'/index.php?view=image&fid='.$this->{'Id'}; + } // end function getImageSrc +} # end class +?> diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 571eb48d8..7636688ec 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -230,6 +230,7 @@ $SLANG = array( 'ChooseLogFormat' => 'Choose a log format', 'ChooseLogSelection' => 'Choose a log selection', 'ChoosePreset' => 'Choose Preset', + 'CloneMonitor' => 'Clone Monitor', 'Close' => 'Close', 'Colour' => 'Colour', 'Command' => 'Command', diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index cc99cacbc..d1212aec3 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -30,7 +30,7 @@ function getControlCommands( $monitor ) $cmds['PresetGoto'] = "presetGoto"; $cmds['PresetHome'] = "presetHome"; - if ( !empty($monitor->CanZoom) ) + if ( !empty($monitor->CanZoom()) ) { if ( $monitor->CanZoomCon() ) $cmds['ZoomRoot'] = "zoomCon"; @@ -45,7 +45,7 @@ function getControlCommands( $monitor ) $cmds['ZoomMan'] = "zoomMan"; } - if ( !empty($monitor->CanFocus) ) + if ( !empty($monitor->CanFocus()) ) { if ( $monitor->CanFocusCon() ) $cmds['FocusRoot'] = "focusCon"; @@ -60,7 +60,7 @@ function getControlCommands( $monitor ) $cmds['FocusMan'] = "focusMan"; } - if ( !empty($monitor->CanIris) ) + if ( !empty($monitor->CanIris()) ) { if ( $monitor->CanIrisCon() ) $cmds['IrisRoot'] = "irisCon"; @@ -75,7 +75,7 @@ function getControlCommands( $monitor ) $cmds['IrisMan'] = "irisMan"; } - if ( !empty($monitor->CanWhite) ) + if ( !empty($monitor->CanWhite()) ) { if ( $monitor->CanWhiteCon() ) $cmds['WhiteRoot'] = "whiteCon"; @@ -89,7 +89,7 @@ function getControlCommands( $monitor ) $cmds['WhiteMan'] = "whiteMan"; } - if ( !empty($monitor->CanGain) ) + if ( !empty($monitor->CanGain()) ) { if ( $monitor->CanGainCon() ) $cmds['GainRoot'] = "gainCon"; @@ -103,7 +103,7 @@ function getControlCommands( $monitor ) $cmds['GainMan'] = "gainMan"; } - if ( !empty($monitor->CanMove) ) + if ( !empty($monitor->CanMove()) ) { if ( $monitor->CanMoveCon() ) { @@ -246,9 +246,9 @@ function controlPanTilt( $monitor, $cmds )
CanPan; - $hasTilt = $monitor->CanTilt; - $hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag; + $hasPan = $monitor->CanPan(); + $hasTilt = $monitor->CanTilt(); + $hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag(); ?>
@@ -278,7 +278,7 @@ function controlPresets( $monitor, $cmds ) $labels[$row['Preset']] = $row['Label']; } - $presetBreak = (int)(($monitor->NumPresets+1)/((int)(($monitor->NumPresets-1)/MAX_PRESETS)+1)); + $presetBreak = (int)(($monitor->NumPresets()+1)/((int)(($monitor->NumPresets()-1)/MAX_PRESETS)+1)); ob_start(); ?> @@ -286,7 +286,7 @@ function controlPresets( $monitor, $cmds )
NumPresets; $i++ ) + for ( $i = 1; $i <= $monitor->NumPresets(); $i++ ) { ?>" value="" onclick="controlCmd('');"/> @@ -599,9 +598,9 @@ function exportEventImagesMaster( $eids ) foreach ($eids as $eid) { //get monitor id and event id $sql = 'SELECT E.MonitorId, E.StartTime, E.Id - FROM Monitors AS M INNER JOIN Events AS E ON (M.Id = E.MonitorId) - WHERE E.Id = ? - '; + FROM Monitors AS M INNER JOIN Events AS E ON (M.Id = E.MonitorId) + WHERE E.Id = ? + '; $event = dbFetchOne( $sql, NULL, array( $eid ) ); $eventMonitorId[$eid] = $event['MonitorId']; $eventPath[$eid] = mygetEventPath( $event ); diff --git a/web/skins/classic/js/classic.js b/web/skins/classic/js/classic.js index 6ce2e21bb..729d4121c 100644 --- a/web/skins/classic/js/classic.js +++ b/web/skins/classic/js/classic.js @@ -48,7 +48,7 @@ var popupSizes = { 'log': { 'width': 1080, 'height': 720 }, 'login': { 'width': 720, 'height': 480 }, 'logout': { 'width': 260, 'height': 100 }, - 'monitor': { 'width': 450, 'height': 440 }, + 'monitor': { 'width': 700, 'height': 640 }, 'monitorpreset':{ 'width': 440, 'height': 200 }, 'monitorprobe': { 'width': 500, 'height': 240 }, 'monitorselect':{ 'width': 160, 'height': 200 }, diff --git a/web/skins/classic/js/flat.js b/web/skins/classic/js/flat.js index 143bbfce6..d9cf43dc5 100644 --- a/web/skins/classic/js/flat.js +++ b/web/skins/classic/js/flat.js @@ -48,7 +48,7 @@ var popupSizes = { 'log': { 'width': 1080, 'height': 720 }, 'login': { 'width': 720, 'height': 480 }, 'logout': { 'width': 260, 'height': 150 }, - 'monitor': { 'width': 600, 'height': 780 }, + 'monitor': { 'width': 800, 'height': 780 }, 'monitorpreset':{ 'width': 440, 'height': 200 }, 'monitorprobe': { 'width': 500, 'height': 240 }, 'monitorselect':{ 'width': 160, 'height': 200 }, diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 84beadb89..467b5d642 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -21,7 +21,7 @@ xhtmlHeaders( __FILE__, translate('Console') ); - + @@ -54,7 +54,9 @@ if ( canEdit('Monitors') ) if ( $show_storage_areas ) { $columns += 1; } echo $columns; ?>"> - + + + '.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?> - Name(); ?> @@ -113,9 +115,9 @@ echo $Server->Name(); '.$shortpath.'', canEdit( 'Monitors' ) ) ?> diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index f4f205502..3a9e36be6 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -27,7 +27,7 @@ if ( !canView( 'Events' ) ) $eid = validInt( $_REQUEST['eid'] ); $fid = !empty($_REQUEST['fid'])?validInt($_REQUEST['fid']):1; -$sql = 'SELECT E.*,M.Name AS MonitorName,M.Width,M.Height,M.DefaultRate,M.DefaultScale,M.VideoWriter,M.SaveJPEGs,M.Orientation,M.LabelFormat FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?'; +$sql = 'SELECT E.*,M.Name AS MonitorName,E.Width,E.Height,M.DefaultRate,M.DefaultScale,M.VideoWriter,M.SaveJPEGs,M.Orientation,M.LabelFormat FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?'; $sql_values = array( $eid ); if ( $user['MonitorIds'] ) { diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index 582ecb55f..9aa544fb8 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -23,6 +23,7 @@ if ( !canView( 'Events' ) ) $view = "error"; return; } +require_once('includes/Frame.php'); $eid = validInt($_REQUEST['eid']); if ( !empty($_REQUEST['fid']) ) @@ -38,58 +39,60 @@ if ( !empty($fid) ) { } else { $frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $event['MaxScore'] ) ); } +$frame = new Frame( $frame ); $maxFid = $event['Frames']; $firstFid = 1; -$prevFid = $frame['FrameId']-1; -$nextFid = $frame['FrameId']+1; +$prevFid = $frame->FrameId()-1; +$nextFid = $frame->FrameId()+1; $lastFid = $maxFid; -$alarmFrame = $frame['Type']=='Alarm'; +$alarmFrame = $frame->Type()=='Alarm'; if ( isset( $_REQUEST['scale'] ) ) $scale = validInt($_REQUEST['scale']); else $scale = max( reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); -$imageData = getImageSrc( $event, $frame, $scale, (isset($_REQUEST['show']) && $_REQUEST['show']=="capt") ); +$imageData = getImageSrc( $event, $frame->FrameId(), $scale, (isset($_REQUEST['show']) && $_REQUEST['show']=="capt") ); $imagePath = $imageData['thumbPath']; $eventPath = $imageData['eventPath']; -$dImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-d.jpg", $eventPath, $frame['FrameId'] ); -$rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $frame['FrameId'] ); +$dImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-d.jpg", $eventPath, $frame->FrameId() ); +$rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $frame->FrameId() ); $focusWindow = true; -xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame['FrameId'] ); +xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame->FrameId() ); ?>

- + "><?php echo $frame['EventId']." class=""/> +if ( $imageData['hasAnalImage'] ) { ?>"> +<?php echo $frame->EventId().FrameId() ?>" class=""/>

- 1 ) { ?> +FrameId() > 1 ) { ?> - 1 ) { ?> +FrameId() > 1 ) { ?> - +FrameId() < $maxFid ) { ?> - +FrameId() < $maxFid ) { ?>

diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 5182a5fd5..99f175c23 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -1,3 +1,6 @@ +var jsTranslatedAddText; +var jsTranslatedCloneText; + function setButtonStates( element ) { var form = element.form; @@ -15,9 +18,36 @@ function setButtonStates( element ) } $(element).getParent( 'tr' ).toggleClass( 'highlight' ); form.editBtn.disabled = (checked!=1); + form.addBtn.value = (checked==1) ? jsTranslatedCloneText:jsTranslatedAddText; + form.deleteBtn.disabled = (checked==0); } +function addMonitor( element) +{ + + var form = element.form; + var dupParam; + var monitorId=-1; + if (form.addBtn.value == jsTranslatedCloneText) + { + // get the value of the first checkbox + for ( var i = 0; i < form.elements.length; i++ ) + { + if ( form.elements[i].type == "checkbox" ) + { + if ( form.elements[i].checked ) + { + monitorId = form.elements[i].value; + break; + } + } + } + } + dupParam = (monitorId == -1 ) ? '': '&dupId='+monitorId; + createPopup( '?view=monitor'+dupParam, 'zmMonitor0','monitor' ); +} + function editMonitor( element ) { var form = element.form; @@ -55,6 +85,8 @@ function reloadWindow() function initPage() { + jsTranslatedAddText = translatedAddText; + jsTranslatedCloneText = translatedCloneText; reloadWindow.periodical( consoleRefreshTimeout ); if ( showVersionPopup ) createPopup( '?view=version', 'zmVersion', 'version' ); diff --git a/web/skins/classic/views/js/console.js.php b/web/skins/classic/views/js/console.js.php index 93cf0cdb7..98417a985 100644 --- a/web/skins/classic/views/js/console.js.php +++ b/web/skins/classic/views/js/console.js.php @@ -26,7 +26,7 @@ elseif ( ZM_DYN_SHOW_DONATE_REMINDER ) ?> var showVersionPopup = ; var showDonatePopup = ; - - +var translatedAddText = ""; +var translatedCloneText = ""; diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 58e4a1e19..04f29d049 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -58,80 +58,88 @@ if ( ! empty($_REQUEST['mid']) ) { } else { $nextId = getTableAutoInc( 'Monitors' ); - $monitor = new Monitor(); - $monitor->set( array( - 'Id' => 0, - 'Name' => translate('Monitor').'-'.$nextId, - 'Function' => "Monitor", - 'Enabled' => true, - 'LinkedMonitors' => "", - 'Type' => "", - 'Device' => "/dev/video0", - 'Channel' => "0", - 'Format' => 0x000000ff, - 'Protocol' => "", - 'Method' => "", - 'Host' => "", - 'Path' => "", - 'Options' => "", - 'Port' => "80", - 'User' => "", - 'Pass' => "", - 'Colours' => 3, - 'Palette' => 0, - 'Width' => "320", - 'Height' => "240", - 'Orientation' => "0", - 'Deinterlacing' => 0, - 'RTSPDescribe' => 0, - 'SaveJPEGs' => "3", - 'VideoWriter' => "0", - 'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", - 'RecordAudio' => '0', - 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S', - 'LabelX' => 0, - 'LabelY' => 0, - 'LabelSize' => 1, - 'ImageBufferCount' => 50, - 'WarmupCount' => 25, - 'PreEventCount' => 25, - 'PostEventCount' => 25, - 'StreamReplayBuffer' => 1000, - 'AlarmFrameCount' => 1, - 'Controllable' => 0, - 'ControlId' => "", - 'ControlType' => 0, - 'ControlDevice' => "", - 'ControlAddress' => "", - 'AutoStopTimeout' => "", - 'TrackMotion' => 0, - 'TrackDelay' => "", - 'ReturnLocation' => -1, - 'ReturnDelay' => "", - 'SectionLength' => 600, - 'FrameSkip' => 0, - 'MotionFrameSkip' => 0, - 'EventPrefix' => 'Event-', - 'AnalysisFPS' => "", - 'AnalysisUpdateDelay' => 0, - 'MaxFPS' => "", - 'AlarmMaxFPS' => "", - 'FPSReportInterval' => 1000, - 'RefBlendPerc' => 6, - 'AlarmRefBlendPerc' => 6, - 'DefaultView' => 'Events', - 'DefaultRate' => '100', - 'DefaultScale' => '100', - 'SignalCheckColour' => '#0000c0', - 'WebColour' => 'red', - 'Exif' => '0', - 'Triggers' => "", - 'V4LMultiBuffer' => '', - 'V4LCapturesPerFrame' => 1, - 'ServerId' => $Server['Id'], - 'StorageId' => '', - ) ); -} + if ( ! empty( $_REQUEST['dupId'] ) ) { + $monitor = new Monitor( $_REQUEST['dupId'] ); + if ( ZM_OPT_X10 ) + $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId']) ); + $clonedName = $monitor->Name(); + $monitor->Name( translate('Monitor').'-'.$nextId ); + } else { + $monitor = new Monitor(); + $monitor->set( array( + 'Id' => 0, + 'Name' => translate('Monitor').'-'.$nextId, + 'Function' => "Monitor", + 'Enabled' => true, + 'LinkedMonitors' => "", + 'Type' => "", + 'Device' => "/dev/video0", + 'Channel' => "0", + 'Format' => 0x000000ff, + 'Protocol' => "", + 'Method' => "", + 'Host' => "", + 'Path' => "", + 'Options' => "", + 'Port' => "80", + 'User' => "", + 'Pass' => "", + 'Colours' => 3, + 'Palette' => 0, + 'Width' => "320", + 'Height' => "240", + 'Orientation' => "0", + 'Deinterlacing' => 0, + 'RTSPDescribe' => 0, + 'SaveJPEGs' => "3", + 'VideoWriter' => "0", + 'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", + 'RecordAudio' => '0', + 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S', + 'LabelX' => 0, + 'LabelY' => 0, + 'LabelSize' => 1, + 'ImageBufferCount' => 50, + 'WarmupCount' => 25, + 'PreEventCount' => 25, + 'PostEventCount' => 25, + 'StreamReplayBuffer' => 1000, + 'AlarmFrameCount' => 1, + 'Controllable' => 0, + 'ControlId' => "", + 'ControlType' => 0, + 'ControlDevice' => "", + 'ControlAddress' => "", + 'AutoStopTimeout' => "", + 'TrackMotion' => 0, + 'TrackDelay' => "", + 'ReturnLocation' => -1, + 'ReturnDelay' => "", + 'SectionLength' => 600, + 'FrameSkip' => 0, + 'MotionFrameSkip' => 0, + 'EventPrefix' => 'Event-', + 'AnalysisFPS' => "", + 'AnalysisUpdateDelay' => 0, + 'MaxFPS' => "", + 'AlarmMaxFPS' => "", + 'FPSReportInterval' => 1000, + 'RefBlendPerc' => 6, + 'AlarmRefBlendPerc' => 6, + 'DefaultView' => 'Events', + 'DefaultRate' => '100', + 'DefaultScale' => '100', + 'SignalCheckColour' => '#0000c0', + 'WebColour' => 'red', + 'Exif' => '0', + 'Triggers' => "", + 'V4LMultiBuffer' => '', + 'V4LCapturesPerFrame' => 1, + 'ServerId' => $Server['Id'], + 'StorageId' => '', + ) ); + } # end if $_REQUEST['dupID'] +} # end if $_REQUEST['mid'] if ( ZM_OPT_X10 && empty($x10Monitor) ) { $x10Monitor = array( @@ -143,6 +151,7 @@ if ( ZM_OPT_X10 && empty($x10Monitor) ) { function fourcc( $a, $b, $c, $d ) { return( ord($a) | (ord($b) << 8) | (ord($c) << 16) | (ord($d) << 24) ); + } if ( isset( $_REQUEST['newMonitor'] ) ) { @@ -455,23 +464,22 @@ $videowriteropts = array( xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor->Name) ); ?> -
- +
diff --git a/web/views/image.php b/web/views/image.php index 28843f96d..8fe5ab558 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -40,6 +40,7 @@ if ( !canView( 'Events' ) ) require_once('includes/Storage.php'); require_once('includes/Event.php'); +require_once('includes/Frame.php'); header( 'Content-type: image/jpeg' ); @@ -67,6 +68,12 @@ if ( empty($_REQUEST['path']) ) $Event = new Event( $_REQUEST['eid'] ); $Storage = $Event->Storage(); $path = $Event->Relative_Path().'/'.sprintf("%'.0".ZM_EVENT_IMAGE_DIGITS.'d',$_REQUEST['fid']).'-capture.jpg'; + } else { + # If we are only specifying fid, then the fid must be the primary key into the frames table. But when the event is specified, then it is the frame # + $Frame = new Frame( $_REQUEST['fid'] ); + $Event = new Event( $Frame->EventId() ); + $Storage = $Event->Storage(); + $path = $Event->Relative_Path().'/'.sprintf("%'.0".ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-capture.jpg'; } } else { $errorText = "No image path";