Merge branch 'storageareas' of github.com:ZoneMinder/ZoneMinder into storageareas

This commit is contained in:
Isaac Connor 2016-04-30 10:09:52 -04:00
commit 408fba8d24
115 changed files with 28012 additions and 27185 deletions

View File

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

View File

@ -3,6 +3,19 @@
set -e
if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group.
chown www-data:root /var/log/zm
chown www-data:www-data /var/lib/zm
if [ -z "$2" ]; then
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
fi
# Do this every time the package is installed or upgraded
if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/etc/init.d/mysql" ]; then
#
# Get mysql started if it isn't
@ -15,39 +28,26 @@ if [ "$1" = "configure" ]; then
# test if database if already present...
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
echo 'grant lock tables, alter,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
# This creates the user.
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
# Ensure zoneminder is stopped
invoke-rc.d zoneminder stop || true
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
invoke-rc.d zoneminder start || true
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo 'mysql not found, assuming remote server.'
fi
chown www-data:www-data /var/log/zm
chown www-data:www-data /var/lib/zm/
if [ -z "$2" ]; then
chown www-data:www-data -R /var/cache/zoneminder
fi
fi
# Ensure zoneminder is stopped...
if [ -x "/etc/init.d/zoneminder" ]; then
if invoke-rc.d zoneminder status ; then
invoke-rc.d zoneminder stop || exit $?
fi
fi
if [ "$1" = "configure" ]; then
if [ -z "$2" ]; then
chown www-data:www-data /var/log/zm
chown www-data:www-data /var/lib/zm/
chown www-data:www-data -R /var/cache/zoneminder
else
chown www-data:www-data /var/log/zm
zmupdate.pl
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
fi
fi
#DEBHELPER#

View File

@ -1,3 +1,9 @@
zoneminder (1.30.2-trusty-2016042801) trusty; urgency=medium
* Merge video
-- Isaac Connor <iconnor@connortechnology.com> Thu, 28 Apr 2016 12:54:08 -0400
zoneminder (1.28.1+1-vivid-SNAPSHOT2015081701) vivid; urgency=medium
* include api, switch to cmake build

View File

@ -3,10 +3,50 @@
set -e
if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
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
if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/etc/init.d/mysql" ]; then
#
# Get mysql started if it isn't
#
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
invoke-rc.d mysql start
fi
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
# test if database if already present...
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
# This creates the user.
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
# Ensure zoneminder is stopped
invoke-rc.d zoneminder stop || true
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
invoke-rc.d zoneminder start || true
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo 'mysql not found, assuming remote server.'
fi
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
fi
fi

View File

@ -1,3 +1,15 @@
zoneminder (1.30.2-trusty-2016033001) trusty; urgency=medium
* merge master
-- Isaac Connor <iconnor@connortechnology.com> Wed, 30 Mar 2016 14:09:48 -0400
zoneminder (1.30.2-trusty-2016032901) trusty; urgency=medium
* filter fixes, merge options rework by Kyle
-- Isaac Connor <iconnor@connortechnology.com> Tue, 29 Mar 2016 12:27:57 -0400
zoneminder (1.30.2-trusty-2016030702) trusty; urgency=medium
*

View File

@ -6,6 +6,7 @@ Uploaders: Vagrant Cascadian <vagrant@debian.org>
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-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

View File

@ -2,28 +2,57 @@
set -e
. /etc/zm/zm.conf
if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
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
# Test for database presence to avoid failure of zmupdate.pl
if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/etc/init.d/mysql" ]; then
#
# Get mysql started if it isn't
#
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
deb-systemd-invoke start mysql.service || exit $?
fi
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
# test if database if already present...
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
# This creates the user.
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
if [ "$ZM_DB_HOST" = "localhost" ]; then
echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
# Run the ZoneMinder update tool
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
deb-systemd-invoke start zoneminder.service || exit $?
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo 'mysql not found, assuming remote server.'
fi
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
fi;
fi
fi

View File

@ -514,6 +514,8 @@ You do not need to rebuild ZM for X10 support. You will need to install the perl
Extending Zoneminder
------------------------
.. _runstate_cron_example:
How can I get ZM to do different things at different times of day or week?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -67,8 +67,14 @@ own empty screen.
* **D**: This is the core of ZoneMinder - recording events. It gives you a count of how many events were recorded over the hour, day, week, month.
* **E**: These are the "Zones". Zones are areas within the camera that you mark as 'hotspots' for motion detection. Simply put, when you first configure your monitors (cameras), by default Zoneminder uses the entire field of view of the camera to detect motion. You may not want this. You may want to create "zones" specifically for detecting motion and ignore others. For example, lets consider a room with a fan that spins. You surely don't want to consider the fan moving continuously a reason for triggering a record? Probably not - in that case, you'd leave the fan out while making your zones.
* **F**: This is the "source" column that tells you the type of the camera - if its an IP camera, a USB camera or more. In this example, they are all IP cameras. Note the color red on item F ? Well that means there is something wrong with that camera. No wonder the log also shows red. Good indication for you to tap on logs and investigate
* **G**: This defines how Zoneminder will record events. There are various modes. In brief Modect == record if a motion is detected,Record = always record 24x7, Mocord = always record PLUS detect motion, Monitor = just provide a live view but don't record anytime, Nodect = Don't record till an externa entity via zmtrigger tells Zoneminder to (this is advanced usage).
* **G**: This defines how Zoneminder will record events. There are various modes. In brief Modect == record if a motion is detected,Record = always record 24x7, Mocord = always record PLUS detect motion, Monitor = just provide a live view but don't record anytime, Nodect = Don't record till an external entity via zmtrigger tells Zoneminder to (this is advanced usage).
* **H**: If you click on these links you can view a "Montage" of all your configured monitors or cycle through each one
* **I**: One of the most often missed features is the ability of ZoneMinder to maintain "run states". If you click on the "Running" text, ZoneMinder brings up a popup that allows you to define additional "states" (referred to as runstates). A runstate is essentially a snapshot that records the state of each monitor and you can switch between states easily. For example, you might have a run state defined that switches all monitors to "monitor" mode in which they are not recording anything while another state that sets some of the monitors to "modect". Why would you want this? A great example is to disable recording when you are at home and enable when you are away, based on time of day or other triggers. You can switch states by selecting an appropriate state manually, or do it automatically via cron jobs, for example. An example of using cron to automatically switch is provided in the :ref:`FAQ <runstate_cron_example>`. More esoteric examples of switching run states based on phone location can be found `here <https://forums.zoneminder.com/viewtopic.php?f=9&t=23026>`__.
Here is an example of multiple run states that I've defined. Each one of these runstates changes the mode of specific monitors depending on time of day and other conditions. Use your imagination to decide which conditions require state changes.
.. image:: images/runstates.png
Adding Monitors

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

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

View File

@ -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 = $selectFrameDataSth->execute( $event->{Id} );
my $frame = $selectFrameDataSth->fetchrow_hashref();
if ( $frame ) {
$res = $updateUnclosedEventsSth->execute
(
sprintf("%s%d%s",
$event->{Prefix},
$Monitors{$event->{MonitorId}}->{EventPrefix},
$event->{Id},
RECOVER_TAG
),
$event->{EndTime},
$event->{Length},
$event->{Frames},
$event->{AlarmFrames},
$event->{TotScore},
$event->{AlarmFrames}
? int($event->{TotScore} / $event->{AlarmFrames})
$frame->{EndTime},
$frame->{EndTimeStamp} - $event->{TimeStamp},
$frame->{Frames},
$frame->{AlarmFrames},
$frame->{TotScore},
$frame->{AlarmFrames}
? int($frame->{TotScore} / $frame->{AlarmFrames})
: 0
,
$event->{MaxScore},
$frame->{MaxScore},
RECOVER_TEXT,
$event->{Id}
) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() );
} else {
Error("SHOULD DELETE");
} # end if has frame data
}
}

View File

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

View File

@ -779,10 +779,32 @@ sub sendEmail
Disposition => "attachment"
);
}
### Send the Message
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();
}
else
{
my $mail = MIME::Entity->build(

View File

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

View File

@ -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 );
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 );
return NULL;
mysql_free_result( result_set );
result_set = NULL;
return result_set;
}
MYSQL_ROW dbrow = mysql_fetch_row( result );
mysql_free_result( result );
if ( ! dbrow ) {
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 ) );
return NULL;
} else {
Debug(3, "Succes");
}
return dbrow;
return result_set;
}
zmDbRow::~zmDbRow() {
if ( result_set )
mysql_free_result( result_set );
}

View File

@ -22,6 +22,21 @@
#include <mysql/mysql.h>
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" */

View File

@ -840,7 +840,7 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time )
return( true );
}
bool EventStream::loadInitialEventData( int init_event_id, int init_frame_id )
bool EventStream::loadInitialEventData( int init_event_id, unsigned int init_frame_id )
{
loadEventData( init_event_id );

View File

@ -49,23 +49,23 @@ class Monitor;
//
class Event
{
friend class EventStream;
friend class EventStream;
protected:
protected:
static bool initialised;
static char capture_file_format[PATH_MAX];
static char analyse_file_format[PATH_MAX];
static char general_file_format[PATH_MAX];
static char video_file_format[PATH_MAX];
protected:
protected:
static int sd;
public:
public:
typedef std::set<std::string> StringSet;
typedef std::map<std::string,StringSet> StringSetMap;
protected:
protected:
typedef enum { NORMAL, BULK, ALARM } FrameType;
struct PreAlarmData
@ -79,7 +79,7 @@ protected:
static int pre_alarm_count;
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
protected:
protected:
unsigned int id;
Monitor *monitor;
struct timeval start_time;
@ -99,10 +99,10 @@ protected:
char timecodes_name[PATH_MAX];
char timecodes_file[PATH_MAX];
protected:
protected:
int last_db_frame;
protected:
protected:
static void Initialise()
{
if ( initialised )
@ -118,11 +118,11 @@ protected:
void createNotes( std::string &notes );
public:
public:
static bool OpenFrameSocket( int );
static bool ValidateFrameSocket( int );
public:
public:
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false );
~Event();
@ -144,10 +144,10 @@ public:
void AddFrames( int n_frames, Image **images, struct timeval **timestamps );
void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL );
private:
private:
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );
public:
public:
static const char *getSubPath( struct tm *time )
{
static char subpath[PATH_MAX] = "";
@ -163,7 +163,7 @@ public:
return video_file;
}
public:
public:
static int PreAlarmCount()
{
return( pre_alarm_count );
@ -204,10 +204,10 @@ public:
class EventStream : public StreamBase
{
public:
public:
typedef enum { MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
protected:
protected:
struct FrameData {
//unsigned long id;
time_t timestamp;
@ -230,31 +230,31 @@ protected:
char video_file[PATH_MAX];
};
protected:
protected:
static const int STREAM_PAUSE_WAIT = 250000; // Microseconds
static const StreamMode DEFAULT_MODE = MODE_SINGLE;
protected:
protected:
StreamMode mode;
bool forceEventChange;
protected:
protected:
int curr_frame_id;
double curr_stream_time;
EventData *event_data;
protected:
protected:
bool loadEventData( int event_id );
bool loadInitialEventData( int init_event_id, int init_frame_id );
bool loadInitialEventData( int init_event_id, unsigned int init_frame_id );
bool loadInitialEventData( int monitor_id, time_t event_time );
void checkEventLoaded();
void processCommand( const CmdMsg *msg );
bool sendFrame( int delta_us );
public:
public:
EventStream()
{
mode = DEFAULT_MODE;
@ -266,7 +266,7 @@ public:
event_data = 0;
}
void setStreamStart( int init_event_id, int init_frame_id=0 )
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 )
{
loadInitialEventData( init_event_id, init_frame_id );
loadMonitor( event_data->monitor_id );

View File

@ -167,12 +167,21 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
#endif
/* Check the buffer sizes */
#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;
}
#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,11 +195,27 @@ 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 ) ) {
#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 ) ) {
#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;
}
@ -338,15 +363,9 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
AVStream *st = ic->streams[i];
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
unsigned char *separator = ic->dump_separator;
char **codec_separator = (char **)av_opt_ptr(st->codec->av_class, st->codec, "dump_separator");
int use_format_separator = !*codec_separator;
char separator = '\n';
if (use_format_separator)
*codec_separator = av_strdup((const char *)separator);
avcodec_string(buf, sizeof(buf), st->codec, is_output);
if (use_format_separator)
av_freep(codec_separator);
Debug(3, " Stream #%d:%d", index, i);
/* the pid is an important information, so we display it */

View File

@ -48,6 +48,12 @@ extern "C" {
#else
#include <libavcodec/opt.h>
#endif
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
#include <libavutil/imgutils.h>
#else
#include <libavutil/avutil.h>
#endif
#elif HAVE_FFMPEG_AVUTIL_H
#include <ffmpeg/avutil.h>
#include <ffmpeg/base64.h>

View File

@ -61,6 +61,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
mOpenStart = 0;
mReopenThread = 0;
wasRecording = false;
videoStore = NULL;
#if HAVE_LIBSWSCALE
mConvertContext = NULL;
@ -99,6 +100,7 @@ void FfmpegCamera::Initialise()
av_log_set_level( AV_LOG_QUIET );
av_register_all();
avformat_network_init();
}
void FfmpegCamera::Terminate()
@ -191,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) {
@ -350,7 +358,8 @@ int FfmpegCamera::OpenFfmpeg() {
if ( mAudioStreamId == -1 )
Debug( 2, "Unable to locate audio stream in %s", mPath.c_str() );
Debug ( 1, "Found video stream" );
Debug ( 3, "Found video stream at index %d", mVideoStreamId );
Debug ( 3, "Found audio stream at index %d", mAudioStreamId );
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
@ -392,12 +401,17 @@ 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);
}
Debug ( 1, "Validated imagesize" );
Debug ( 1, "Validated imagesize %d", pSize );
#if HAVE_LIBSWSCALE
Debug ( 1, "Calling sws_isSupportedInput" );
@ -579,9 +593,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
//Keep the last keyframe so we can establish immediate video
/*if(packet.flags & AV_PKT_FLAG_KEY)
av_copy_packet(&lastKeyframePkt, &packet);*/
if(packet.flags & AV_PKT_FLAG_KEY) {
//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
}
//Video recording
if ( recording && !wasRecording ) {
@ -592,6 +608,9 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
wasRecording = true;
strcpy(oldDirectory, event_file);
// Need to write out all the frames from the last keyframe?
} else if ( ( ! recording ) && wasRecording && videoStore ) {
Info("Deleting videoStore instance");
delete videoStore;
@ -649,9 +668,10 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
}
if ( videoStore && recording ) {
if ( record_audio ) {
Debug(3, "Recording audio packet" );
Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet.stream_index );
//Write the packet to our video store
int ret = videoStore->writeAudioFramePacket(&packet, mFormatContext->streams[packet.stream_index]); //FIXME no relevance of last key frame
//FIXME no relevance of last key frame
int ret = videoStore->writeAudioFramePacket( &packet, mFormatContext->streams[packet.stream_index] );
if ( ret < 0 ) {//Less than zero and we skipped a frame
av_free_packet( &packet );
return 0;
@ -661,7 +681,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
}
}
} else {
#if LIBAVUTIL_VERSION_CHECK(54, 23, 0, 23, 0)
Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codec->codec_type) );
#else
Debug( 3, "Some other stream index %d", packet.stream_index );
#endif
}
av_free_packet( &packet );
} // end while ! frameComplete

View File

@ -64,7 +64,9 @@ protected:
bool wasRecording;
VideoStore *videoStore;
char oldDirectory[4096];
//AVPacket lastKeyframePkt;
// Last Key frame
AVPacket lastKeyframePkt;
#if HAVE_LIBSWSCALE
struct SwsContext *mConvertContext;

View File

@ -644,7 +644,11 @@ LocalCamera::LocalCamera(
if ( !tmpPicture )
Fatal( "Could not allocate temporary picture" );
#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

View File

@ -615,7 +615,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
{
int priority = smSyslogPriorities[level];
//priority |= LOG_DAEMON;
syslog( priority, "%s [%s]", classString, syslogStart );
syslog( priority, "%s [%s] [%s]", classString, mId.c_str(), syslogStart );
}
if ( level <= FATAL )

View File

@ -1119,13 +1119,13 @@ 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 );
EventStream *stream = new EventStream();
stream->setStreamStart( event_id, 1 );
stream->setStreamStart( event_id, (unsigned int)1 );
zone_image = stream->getImage();
} else {
Error("Unable to load an event for monitor %d", id );
@ -1279,6 +1279,7 @@ bool Monitor::Analyse()
{
if ( shared_data->last_read_index == shared_data->last_write_index )
{
// I wonder how often this happens. Maybe if this happens we should sleep or something?
return( false );
}
@ -1299,8 +1300,10 @@ bool Monitor::Analyse()
if ( read_margin < 0 ) read_margin += image_buffer_count;
int step = 1;
// Isn't read_margin always > 0 here?
if ( read_margin > 0 )
{
// TODO explain this so... 90% of image buffer / 50% of read margin?
step = (9*image_buffer_count)/(5*read_margin);
}
@ -1380,6 +1383,7 @@ bool Monitor::Analyse()
if ( static_undef )
{
// Sure would be nice to be able to assume that these were already initialized. It's just 1 compare/branch, but really not neccessary.
static_undef = false;
timestamps = new struct timeval *[pre_event_count];
images = new Image *[pre_event_count];
@ -1392,6 +1396,7 @@ bool Monitor::Analyse()
bool signal_change = (signal != last_signal);
//Set video recording flag for event start constructor and easy reference in code
// TODO: Use enum instead of the # 2. Makes for easier reading
bool videoRecording = ((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo());
if ( trigger_data->trigger_state != TRIGGER_OFF )
@ -2177,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(
@ -2190,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,
@ -2344,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(
@ -2355,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,
@ -2374,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,
@ -2526,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,
@ -2683,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,
@ -2765,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 ) );
}
@ -2864,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;
@ -2880,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,
@ -2903,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,
@ -2921,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,
@ -2942,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,
@ -2959,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,
@ -2979,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,
@ -2999,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,
@ -3281,191 +3271,6 @@ bool Monitor::closeEvent()
return( false );
}
//-----------------------------------------
/*
* NOTE Nextime's comment:
*
* OurCheckAlarms seems to be called only by DetectBlack method, and DetectBlack
* method is only called in a commented line instead of DetectMotion in zm_monitor.cpp.
*
* Probably this is just a dead code used for debugghing purpose, so, instead of fixing it
* it seems to be safe to just comment it out.
*
* Anyway, the issues with this code is that it assumes the image to be an RGB24 image,
* so, as i've discussed on IRC with mastertheknife, changes needed are:
*
* Check if the image is 24 or 32 bits ( pImage->Colours() says 3 for 24 and 4 for 32 bits,
* comparing it with ZM_COLOUR_RGB24 or ZM_COLOUR_RGB32 is the way ), and then
* manage che check using RGB_VAL_RED() and so on macros instead of just RED().
*
* Be careful that in 32 bit images we need to check also where the alpha channel is, so,
* (RGBA and BGRA) or (ABGR and ARGB) aren't the same!
*
* To check black pixels in 32 bit images i can do a more efficient way using
* RGBA_ZERO_ALPHA(pixel) == RGBA_ZERO_ALPHA(RGB_BLACK), but before of that i need to
* check where the alpha channel is and maybe convert it.
* Maybe this won't work as they assign "23" to black_thr, so, they are not checking
* if the pixel is black, but just "quasi" black is enough.
*
* Anyway, for the moment, comment out whole part.
*/
/*
bool Monitor::OurCheckAlarms( Zone *zone, const Image *pImage )
{
Info("Entering OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>");
unsigned char black_thr = 23;
int min_alarm_score = 10;
int max_alarm_score = 99;
//bool alarm = false;
unsigned int score;
Polygon zone_polygon = zone->GetPolygon();
Info("Got polygon of a zone. It has %d vertices.", zone_polygon.getNumCoords());
zone->ResetStats();
Info("ResetStats done.");
if ( !zone->CheckOverloadCount() )
{
Info("CheckOverloadCount() return false, we'll return false.");
return( false );
}
Image *pMaskImage = new Image(pImage->Width(), pImage->Height(), ZM_COLOUR_GRAY8, pImage->SubpixelOrder());
Info("Mask image created.");
pMaskImage->Fill(BLACK);
Info("Mask image filled with BLACK.");
if (pImage->Colours() == ZM_COLOUR_GRAY8)
{
Info("Analysed image is not colored! Set score = 0.");
score = 0;
}
else
{
Info("Start processing image.");
//Process image
unsigned char *buffer = (unsigned char*)pImage->Buffer();
unsigned char *mask_buffer = (unsigned char*)pMaskImage->Buffer();
int black_pixels_count = 0;
Info("Loop for black pixels counting and mask filling.");
while (buffer < (pImage->Buffer() + pImage->Size()))
{
if ( (RED(buffer) < black_thr) && (GREEN(buffer) < black_thr) && (BLUE(buffer) < black_thr) )
{
*mask_buffer = WHITE;
black_pixels_count++;
}
buffer += pImage->Colours();
mask_buffer++;
}
if ( !black_pixels_count )
{
delete pMaskImage;
return( false );
}
score = (100*black_pixels_count)/zone_polygon.Area();
Info("Number of black pixels is %d, zone polygon area is %d, score is %d", black_pixels_count, zone_polygon.Area(), score);
if ( min_alarm_score && ( score < min_alarm_score) )
{
delete pMaskImage;
return( false );
}
if ( max_alarm_score && (score > max_alarm_score) )
{
zone->SetOverloadCount(zone->GetOverloadFrames());
delete pMaskImage;
return( false );
}
}
zone->SetScore(score);
Info("Score have been set in zone.");
//Get mask
Rgb alarm_colour = RGB_RED;
Image *tempImage = pMaskImage->HighlightEdges(alarm_colour, &zone_polygon.Extent() );
Info("After HighlightEdges");
zone->SetAlarmImage(tempImage);
Info("After SetAlarmImage");
delete pMaskImage;
Info("After Delete pMaskImage");
delete tempImage;
Info("Leaving OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>");
return true;
}
unsigned int Monitor::DetectBlack(const Image &comp_image, Event::StringSet &zoneSet )
{
Info("Entering DetectBlack >>>>>>>>>>>>>>>>>>>>>>>>>>");
bool alarm = false;
unsigned int score = 0;
if ( n_zones <= 0 ) return( alarm );
// Coord alarm_centre;
// int top_score = -1;
// Find all alarm pixels in active zones
Info("Number of zones to process %d", n_zones);
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
Zone *zone = zones[n_zone];
if ( !zone->IsActive() )
{
continue;
}
Debug( 3, "Checking active zone %s", zone->Label() );
Info( "Checking active zone %s", zone->Label() );
if ( OurCheckAlarms( zone, &comp_image ) )
{
Info("OurCheckAlarm is TRUE!!!!!!");
alarm = true;
score += zone->Score();
zone->SetAlarm();
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
Info( "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
// if ( config.opt_control && track_motion )
// {
// if ( (int)zone->Score() > top_score )
// {
// top_score = zone->Score();
// alarm_centre = zone->GetAlarmCentre();
// }
// }
}
Info( "Finish checking active zone %s", zone->Label() );
}
// if ( top_score > 0 )
// {
// shared_data->alarm_x = alarm_centre.X();
// shared_data->alarm_y = alarm_centre.Y();
//
// Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count );
// }
// else
// {
// shared_data->alarm_x = shared_data->alarm_y = -1;
// }
// This is a small and innocent hack to prevent scores of 0 being returned in alarm state
Info("Leaving DetectBlack <<<<<<<<<<<<<<<<<<<<<<<<<<<");
return( score?score:alarm );
}
*/
//-----------------------------------------------------------------------------------------------
unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet )
{
bool alarm = false;

View File

@ -48,9 +48,9 @@
//
class Monitor
{
friend class MonitorStream;
friend class MonitorStream;
public:
public:
typedef enum
{
QUERY=0,
@ -87,7 +87,7 @@ public:
TAPE
} State;
protected:
protected:
typedef std::set<Zone *> ZoneSet;
typedef enum { GET_SETTINGS=0x1, SET_SETTINGS=0x2, RELOAD=0x4, SUSPEND=0x10, RESUME=0x20 } Action;
@ -218,7 +218,7 @@ protected:
bool hasAlarmed();
};
protected:
protected:
// These are read from the DB and thereafter remain unchanged
unsigned int id;
char name[64];
@ -325,9 +325,9 @@ protected:
int n_linked_monitors;
MonitorLink **linked_monitors;
public:
// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info.
//bool OurCheckAlarms( Zone *zone, const Image *pImage );
public:
// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info.
//bool OurCheckAlarms( Zone *zone, const Image *pImage );
Monitor(
int p_id,
const char *p_name,
@ -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() ); }
@ -505,36 +505,36 @@ public:
#define MOD_ADD( var, delta, limit ) (((var)+(limit)+(delta))%(limit))
class MonitorStream : public StreamBase {
protected:
protected:
typedef struct SwapImage {
bool valid;
struct timeval timestamp;
char file_name[PATH_MAX];
} SwapImage;
private:
private:
SwapImage *temp_image_buffer;
int temp_image_buffer_count;
int temp_read_index;
int temp_write_index;
protected:
protected:
time_t ttl;
protected:
protected:
int playback_buffer;
bool delayed;
int frame_count;
protected:
protected:
bool checkSwapPath( const char *path, bool create_path );
bool sendFrame( const char *filepath, struct timeval *timestamp );
bool sendFrame( Image *image, struct timeval *timestamp );
void processCommand( const CmdMsg *msg );
public:
public:
MonitorStream() : playback_buffer( 0 ), delayed( false ), frame_count( 0 ) {
}
void setStreamBuffer( int p_playback_buffer ) {

View File

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

View File

@ -241,7 +241,12 @@ int RemoteCameraRtsp::PrimeCapture()
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 );
#endif
if( (unsigned int)pSize != imagesize) {
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
}
@ -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,7 +487,13 @@ 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
if ( recording && !wasRecording ) {

View File

@ -47,15 +47,12 @@ RETSIGTYPE zm_die_handler(int signal, siginfo_t * info, void *context)
RETSIGTYPE zm_die_handler(int signal)
#endif
{
#if (defined(__i386__) || defined(__x86_64__))
void *cr2 = 0;
void *ip = 0;
#endif
Error("Got signal %d (%s), crashing", signal, strsignal(signal));
#if (defined(__i386__) || defined(__x86_64__))
// Get more information if available
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
void *ip = 0;
void *cr2 = 0;
if (info && context) {
Debug(1,
@ -65,19 +62,19 @@ RETSIGTYPE zm_die_handler(int signal)
ucontext_t *uc = (ucontext_t *) context;
cr2 = info->si_addr;
#if defined(__x86_64__)
#if defined(__x86_64__)
#ifdef __FreeBSD_kernel__
ip = (void *)(uc->uc_mcontext.mc_rip);
#else
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
#endif
#else
#else
#ifdef __FreeBSD_kernel__
ip = (void *)(uc->uc_mcontext.mc_eip);
#else
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);
#endif
#endif // defined(__x86_64__)
#endif // defined(__x86_64__)
// Print the signal address and instruction pointer if available
if (ip) {
@ -86,11 +83,11 @@ RETSIGTYPE zm_die_handler(int signal)
Error("Signal address is %p, no instruction pointer", cr2);
}
}
#endif // ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
#endif // ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
// Print backtrace if enabled and available
#if ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
#if ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
void *trace[TRACE_SIZE];
int trace_size = 0;
trace_size = backtrace(trace, TRACE_SIZE);
@ -111,7 +108,7 @@ RETSIGTYPE zm_die_handler(int signal)
Info("Backtrace complete, please execute the following command for more information");
Info(cmd);
#endif // ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
#endif // ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
#endif // (defined(__i386__) || defined(__x86_64__)
exit(signal);
}

View File

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

View File

@ -253,7 +253,7 @@ void *Thread::mThreadFunc( void *arg )
Debug( 2, "Invoking thread" );
Thread *thisPtr = (Thread *)arg;
void *status = 0;
thisPtr->status = 0;
try
{
thisPtr->mThreadMutex.lock();
@ -261,19 +261,18 @@ void *Thread::mThreadFunc( void *arg )
thisPtr->mThreadCondition.signal();
thisPtr->mThreadMutex.unlock();
thisPtr->mRunning = true;
int run=(thisPtr->run());
status = (void *)&run;
thisPtr->status = thisPtr->run();
thisPtr->mRunning = false;
Debug( 2, "Exiting thread, status %p", status );
Debug( 2, "Exiting thread, status %p", (void *)&(thisPtr->status) );
return (void *)&(thisPtr->status);
}
catch ( const ThreadException &e )
{
Error( "%s", e.getMessage().c_str() );
thisPtr->mRunning = false;
status = (void *)-1;
Debug( 2, "Exiting thread after exception, status %p", status );
Debug( 2, "Exiting thread after exception, status %p", (void *)-1 );
return (void *)-1;
}
return( status );
}
void Thread::start()

View File

@ -36,7 +36,7 @@ class ThreadException : public Exception
{
private:
#ifndef SOLARIS
pid_t pid() {
pid_t pid() {
pid_t tid;
#ifdef __FreeBSD__
long lwpid;
@ -50,9 +50,9 @@ pid_t pid() {
#endif
#endif
return tid;
}
}
#else
pthread_t pid() { return( pthread_self() ); }
pthread_t pid() { return( pthread_self() ); }
#endif
public:
ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) {
@ -224,6 +224,7 @@ protected:
#endif
bool mStarted;
bool mRunning;
int status; // Used in various funcions to get around return a local variable
protected:
Thread();
@ -253,10 +254,10 @@ return tid;
return( pthread_self() );
}
#endif
void exit( int status = 0 )
void exit( int p_status = 0 )
{
//INFO( "Exiting" );
pthread_exit( (void *)&status );
pthread_exit( (void *)&p_status );
}
static void *mThreadFunc( void *arg );

View File

@ -29,11 +29,12 @@
#include "zm_videostore.h"
extern "C"{
#include "libavutil/time.h"
#include "libavutil/time.h"
}
VideoStore::VideoStore(const char *filename_in, const char *format_in,
AVStream *input_st, AVStream *inpaud_st,
AVStream *input_st,
AVStream *inpaud_st,
int64_t nStartTime) {
AVDictionary *pmetadata = NULL;
@ -46,14 +47,20 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
keyframeMessage = false;
keyframeSkipNumber = 0;
Info("Opening video storage stream %s\n", filename);
Info("Opening video storage stream %s format: %d\n", filename, format);
//Init everything we need
int ret;
av_register_all();
avformat_alloc_output_context2(&oc, NULL, NULL, filename);
ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
if ( ret < 0 ) {
Warning("Could not create video storage stream %s as no output context"
" could be assigned based on filename: %s",
filename,
av_make_error_string(ret).c_str()
);
}
//Couldn't deduce format from filename, trying from format name
if (!oc) {
@ -72,15 +79,15 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
fmt = oc->oformat;
video_st = avformat_new_stream(oc, input_st->codec->codec);
video_st = avformat_new_stream(oc, (AVCodec *)input_st->codec->codec);
if (!video_st) {
Fatal("Unable to create video out stream\n");
}
ret = avcodec_copy_context(video_st->codec, input_st->codec);
if (ret < 0) {
Fatal("Unable to copy input video context to output video context "
"%s\n", av_make_error_string(ret).c_str());
Fatal("Unable to copy input video context to output video context %s\n",
av_make_error_string(ret).c_str());
}
video_st->codec->codec_tag = 0;
@ -89,19 +96,27 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
}
if (inpaud_st) {
audio_st = avformat_new_stream(oc, inpaud_st->codec->codec);
audio_st = avformat_new_stream(oc, (AVCodec *)inpaud_st->codec->codec);
if (!audio_st) {
Fatal("Unable to create audio out stream\n");
}
ret=avcodec_copy_context(audio_st->codec, inpaud_st->codec);
Error("Unable to create audio out stream\n");
audio_st = NULL;
} else {
ret = avcodec_copy_context(audio_st->codec, inpaud_st->codec);
if (ret < 0) {
Fatal("Unable to copy audio context %s\n", av_make_error_string(ret).c_str());
}
audio_st->codec->codec_tag = 0;
if ( audio_st->codec->channels > 1 ) {
Warning("Audio isn't mono, changing it.");
audio_st->codec->channels = 1;
}
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
audio_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
}
} else {
Debug(3, "No Audio output stream");
audio_st = NULL;
}
@ -114,11 +129,19 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
}
}
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
//if ((ret = avformat_write_header(ctx, &opts)) < 0) {
//}
//os->ctx_inited = 1;
//avio_flush(ctx->pb);
//av_dict_free(&opts);
/* Write the stream header, if any. */
ret = avformat_write_header(oc, NULL);
if (ret < 0) {
Fatal("Error occurred when writing output file header: %s\n",
zm_dump_stream_format( oc, 0, 0, 1 );
Fatal("Error occurred when writing output file header to %s: %s\n",
filename,
av_make_error_string(ret).c_str());
}
@ -129,7 +152,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
startTime=av_gettime()-nStartTime;//oc->start_time;
Info("VideoStore startTime=%d\n",startTime);
}
} // VideoStore::VideoStore
VideoStore::~VideoStore(){
@ -140,16 +163,24 @@ VideoStore::~VideoStore(){
Debug(3, "Sucess Writing trailer");
}
// I wonder if we should be closing the file first.
// I also wonder if we really need to be doing all the context allocation/de-allocation constantly, or whether we can just re-use it. Just do a file open/close/writeheader/etc.
// What if we were only doing audio recording?
if ( video_st ) {
avcodec_close(video_st->codec);
}
if (audio_st) {
avcodec_close(audio_st->codec);
}
// WHen will be not using a file ?
if (!(fmt->flags & AVFMT_NOFILE)) {
/* Close the output file. */
if ( int rc= avio_close(oc->pb) ) {
if ( int rc = avio_close(oc->pb) ) {
Error("Error closing avio %s", av_err2str( rc ) );
}
} else {
Debug(3, "Not closing avio because we are not writing to a file.");
}
/* free the stream */
@ -247,34 +278,47 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_st){//, AV
int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_st){
if(!audio_st)
if(!audio_st) {
Error("Called writeAudioFramePacket when no audio_st");
return -1;//FIXME -ve return codes do not free packet in ffmpeg_camera at the moment
}
/*if(!keyframeMessage)
return -1;*/
//zm_dump_stream_format( oc, ipkt->stream_index, 0, 1 );
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, video_st->time_base);
// What is this doing? Getting the time of the start of this video chunk? Does that actually make sense?
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, audio_st->time_base);
AVPacket opkt;
av_init_packet(&opkt);
Debug(3, "after init packet" );
//Scale the PTS of the outgoing packet to be the correct time base
if (ipkt->pts != AV_NOPTS_VALUE)
if (ipkt->pts != AV_NOPTS_VALUE) {
Debug(3, "Rescaling output pts");
opkt.pts = av_rescale_q(ipkt->pts-startPts, input_st->time_base, audio_st->time_base) - ost_tb_start_time;
else
} else {
Debug(3, "Setting output pts to AV_NOPTS_VALUE");
opkt.pts = AV_NOPTS_VALUE;
}
//Scale the DTS of the outgoing packet to be the correct time base
if(ipkt->dts == AV_NOPTS_VALUE) {
Debug(4, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
opkt.dts = av_rescale_q(input_st->cur_dts-startDts, AV_TIME_BASE_Q, audio_st->time_base);
Debug(3, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
} else
Debug(4, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
} else {
Debug(4, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
opkt.dts = av_rescale_q(ipkt->dts-startDts, input_st->time_base, audio_st->time_base);
Debug(4, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
}
opkt.dts -= ost_tb_start_time;
// Seems like it would be really weird for the codec type to NOT be audiu
if (audio_st->codec->codec_type == AVMEDIA_TYPE_AUDIO && ipkt->dts != AV_NOPTS_VALUE) {
Debug( 3, "code is audio, dts != AV_NOPTS_VALUE " );
Debug( 4, "code is audio, dts != AV_NOPTS_VALUE " );
int duration = av_get_audio_frame_duration(input_st->codec, ipkt->size);
if(!duration)
duration = input_st->codec->frame_size;
@ -299,7 +343,7 @@ Debug(3, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
if(ret!=0){
Fatal("Error encoding audio frame packet: %s\n", av_make_error_string(ret).c_str());
}
Debug(4,"Success writing audio frame" );
av_free_packet(&opkt);
return 0;
}

View File

@ -62,7 +62,7 @@ int main( int argc, const char *argv[] )
int monitor_id = 0;
time_t event_time = 0;
int event_id = 0;
int frame_id = 1;
unsigned int frame_id = 1;
unsigned int scale = 100;
unsigned int rate = 100;
double maxfps = 10.0;

252
src/zmstreamer.cpp Normal file
View File

@ -0,0 +1,252 @@
//
// ZoneMinder Streamer, $Date: 2010-10-14 23:21:00 +0200 (Thu, 14 Oct 2010) $
// Copyright (C) 2001-2010 Philip Coombes, Chris Kistner
//
// This program is based on revision 3143 of
// http://svn.zoneminder.com/svn/zm/trunk/src/zms.cpp
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*
=head1 NAME
zmstreamer - eyeZM video streamer
=head1 SYNOPSIS
zmstreamer -e <mode>
zmstreamer -o <format>
zmstreamer -u <buffer size>
zmstreamer -f <maximum fps>
zmstreamer -s <scale>
zmstreamer -b <bitrate in bps>
zmstreamer -m <monitor id>
zmstreamer -d <debug mode>
zmstreamer -i
zmstreamer -?
zmstreamer -h
zmstreamer -v
=head1 DESCRIPTION
*DEPRECIATED* The xml skin and all files associated with the xml skin are now
depreciated. Please use the ZoneMinder API instead.
This binary works in conjunction with the XML skin to stream video to iPhones
running the eyeZm app.
=head1 OPTIONS
-e <mode> - Specify output mode: mpeg/jpg/zip/single/raw.
-o <format> - Specify output format.
-u <buffer size> - Specify buffer size in ms.
-f <maximum fps> - Specify maximum framerate.
-s <scale> - Specify scale.
-b <bitrate in bps> - Specify bitrate.
-m <monitor id> - Specify monitor id.
-d <debug mode> - 0 = off, 1 = no streaming, 2 = with streaming.
-i, -?, -h - Display usage information
-v - Print the installed version of ZoneMinder
=cut
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "zm.h"
#include "zm_db.h"
#include "zm_user.h"
#include "zm_signal.h"
#include "zm_monitor.h"
#include "zm_stream.h"
// Possible command-line options
#define OPTIONS "e:o:u:f:s:b:m:d:i:?:h:v"
// Default ZMS values
#define ZMS_DEFAULT_DEBUG 0
#define ZMS_DEFAULT_ID 1
#define ZMS_DEFAULT_BITRATE 100000
#define ZMS_DEFAULT_SCALE 100
#define ZMS_DEFAULT_MODE "mpeg"
#define ZMS_DEFAULT_FORMAT "asf"
#define ZMS_DEFAULT_FPS 25.0
#define ZMS_DEFAULT_BUFFER 1000
int main(int argc, char** argv) {
self = argv[0];
// Set initial values to the default values
int debug = ZMS_DEFAULT_DEBUG;
int id = ZMS_DEFAULT_ID;
int bitrate = ZMS_DEFAULT_BITRATE;
int scale = ZMS_DEFAULT_SCALE;
char mode[32];
sprintf(mode, "%s", ZMS_DEFAULT_MODE);
char format[32];
sprintf(format, "%s", ZMS_DEFAULT_FORMAT);
double maxfps = ZMS_DEFAULT_FPS;
int buffer = ZMS_DEFAULT_BUFFER;
// Parse command-line options
int arg;
while ((arg = getopt(argc, argv, OPTIONS)) != -1) {
switch (arg) {
case 'e':
sprintf(mode, "%s", optarg);
break;
case 'o':
sprintf(format, "%s", optarg);
break;
case 'u':
buffer = atoi(optarg);
break;
case 'f':
maxfps = atof(optarg);
break;
case 's':
scale = atoi(optarg);
break;
case 'b':
bitrate = atoi(optarg);
break;
case 'm':
id = atoi(optarg);
break;
case 'd':
debug = atoi(optarg);
break;
case 'h':
case 'i':
case '?':
printf("-e <mode> : Specify output mode: mpeg/jpg/zip/single/raw. Default = %s\n", ZMS_DEFAULT_MODE);
printf("-o <format> : Specify output format. Default = %s\n", ZMS_DEFAULT_FORMAT);
printf("-u <buffer size> : Specify buffer size in ms. Default = %d\n", ZMS_DEFAULT_BUFFER);
printf("-f <maximum fps> : Specify maximum framerate. Default = %lf\n", ZMS_DEFAULT_FPS);
printf("-s <scale> : Specify scale. Default = %d\n", ZMS_DEFAULT_SCALE);
printf("-b <bitrate in bps> : Specify bitrate. Default = %d\n", ZMS_DEFAULT_BITRATE);
printf("-m <monitor id> : Specify monitor id. Default = %d\n", ZMS_DEFAULT_ID);
printf("-d <debug mode> : 0 = off, 1 = no streaming, 2 = with streaming. Default = 0\n");
printf("-i or -? or -h: This information\n");
printf("-v : This installed version of ZoneMinder\n");
return EXIT_SUCCESS;
case 'v':
std::cout << ZM_VERSION << "\n";
exit(0);
}
}
// Set stream type
StreamBase::StreamType streamtype;
if (!strcasecmp("raw", mode))
streamtype = MonitorStream::STREAM_RAW;
else if (!strcasecmp("mpeg", mode))
streamtype = MonitorStream::STREAM_MPEG;
else if (!strcasecmp("jpg", mode))
streamtype = MonitorStream::STREAM_JPEG;
else if (!strcasecmp("single", mode))
streamtype = MonitorStream::STREAM_SINGLE;
else if (!strcasecmp("zip", mode))
streamtype = MonitorStream::STREAM_ZIP;
else
streamtype = MonitorStream::STREAM_MPEG;
if (debug) {
// Show stream parameters
printf("Stream parameters:\n");
switch (streamtype) {
case MonitorStream::STREAM_MPEG:
printf("Output mode (-e) = %s\n", "mpeg");
printf("Output format (-o) = %s\n", format);
break;
default:
printf("Output mode (-e) = %s\n", mode);
}
printf("Buffer size (-u) = %d ms\n", buffer);
printf("Maximum FPS (-f) = %lf FPS\n", maxfps);
printf("Scale (-s) = %d%%\n", scale);
printf("Bitrate (-b) = %d bps\n", bitrate);
printf("Monitor Id (-m) = %d\n", id);
}
if (debug) {
// Set ZM debugger to print to stdout
printf("Setting up ZoneMinder debugger to print to stdout...");
setenv("ZM_DBG_PRINT", "1", 1);
printf("Done.\n");
}
// Loading ZM configurations
printf("Loading ZoneMinder configurations...");
zmLoadConfig();
printf("Done.\n");
logInit("zmstreamer");
ssedetect();
// Setting stream parameters
MonitorStream stream;
stream.setStreamScale(scale); // default = 100 (scale)
stream.setStreamReplayRate(100); // default = 100 (rate)
stream.setStreamMaxFPS(maxfps); // default = 10 (maxfps)
if (debug) stream.setStreamTTL(1);
else stream.setStreamTTL(0); // default = 0 (ttl)
stream.setStreamQueue(0); // default = 0 (connkey)
stream.setStreamBuffer(buffer); // default = 0 (buffer)
stream.setStreamStart(id); // default = 0 (monitor_id)
stream.setStreamType(streamtype);
if (streamtype == MonitorStream::STREAM_MPEG) {
#if HAVE_LIBAVCODEC
if (debug) printf("HAVE_LIBAVCODEC is set\n");
stream.setStreamFormat(format); // default = "" (format)
stream.setStreamBitrate(bitrate); // default = 100000 (bitrate)
#else
fprintf(stderr, "MPEG streaming is disabled.\nYou should configure with the --with-ffmpeg option and rebuild to use this functionality.\n");
logTerm();
zmDbClose();
return EXIT_FAILURE;
#endif
}
if (debug != 1) {
if (debug) printf("Running stream...");
// Output headers
fprintf(stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION);
time_t now = time(0);
char date_string[64];
strftime(date_string, sizeof (date_string) - 1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
fprintf(stdout, "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n");
fprintf(stdout, "Last-Modified: %s\r\n", date_string);
fprintf(stdout, "Cache-Control: no-store, no-cache, must-revalidate\r\n");
fprintf(stdout, "Cache-Control: post-check=0, pre-check=0\r\n");
fprintf(stdout, "Pragma: no-cache\r\n");
// Run stream
stream.runStream();
}
if (debug) printf("Done.\n");
logTerm();
zmDbClose();
return (EXIT_SUCCESS);
}

View File

@ -756,15 +756,14 @@ int main( int argc, char *argv[] )
if ( function & ZMU_LIST )
{
char sql[ZM_SQL_SML_BUFSIZ];
strncpy( sql, "select Id, Function+0 from Monitors", sizeof(sql) );
std::string sql = "select Id, Function+0 from Monitors";
if ( !verbose )
{
strncat( sql, " where Function != 'None'", sizeof(sql)-strlen(sql) );
sql += "where Function != 'None'";
}
strncat( sql, " order by Id asc", sizeof(sql)-strlen(sql) );
sql += " order by Id asc";
if ( mysql_query( &dbconn, sql ) )
if ( mysql_query( &dbconn, sql.c_str() ) )
{
Error( "Can't run query: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );

76
web/includes/Frame.php Normal file
View File

@ -0,0 +1,76 @@
<?php
require_once( 'database.php' );
require_once( 'Event.php' );
class Frame {
public function __construct( $IdOrRow ) {
$row = NULL;
if ( $IdOrRow ) {
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
$row = dbFetchOne( 'SELECT * FROM Frames WHERE Id=?', NULL, array( $IdOrRow ) );
if ( ! $row ) {
Error("Unable to load Frame record for Id=" . $IdOrRow );
}
} elseif ( is_array( $IdOrRow ) ) {
$row = $IdOrRow;
} else {
Error("Unknown argument passed to Frame Constructor ($IdOrRow)");
return;
}
} # end if isset($IdOrRow)
if ( $row ) {
foreach ($row as $k => $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
?>

View File

@ -527,6 +527,7 @@ if ( !empty($action) )
'DoNativeMotDet' => 'toggle',
'Exif' => 'toggle',
'RTSPDescribe' => 'toggle',
'RecordAudio' => 'toggle',
);
$columns = getTableColumns( 'Monitors' );

View File

@ -104,6 +104,7 @@ define( "CMD_PREV", 12 );
define( "CMD_NEXT", 13 );
define( "CMD_SEEK", 14 );
define( "CMD_VARPLAY", 15 );
define( "CMD_QUIT", 17 );
define( "CMD_QUERY", 99 );
//

View File

@ -217,14 +217,20 @@ function getMimeType( $file )
return( trim( exec( 'file -bi '.escapeshellarg( $file ).' 2>/dev/null' ) ) );
}
function outputVideoStream( $id, $src, $width, $height, $format, $title="" )
{
if ( file_exists( $src ) )
function outputVideoStream( $id, $src, $width, $height, $format, $title="" ) {
echo getVideoStreamHTML( $id, $src, $width, $height, $format, $title );
}
function getVideoStreamHTML( $id, $src, $width, $height, $format, $title="" ) {
$html = '';
$width = validInt($width);
$height = validInt($height);
$title = validHtmlStr($title);
if ( file_exists( $src ) ) {
$mimeType = getMimeType( $src );
else
{
switch( $format )
{
} else {
switch( $format ) {
case 'asf' :
$mimeType = "video/x-ms-asf";
break;
@ -252,118 +258,95 @@ function outputVideoStream( $id, $src, $width, $height, $format, $title="" )
}
if ( !$mimeType || ($mimeType == 'application/octet-stream') )
$mimeType = 'video/'.$format;
$objectTag = false;
if ( ZM_WEB_USE_OBJECT_TAGS )
{
switch( $mimeType )
{
if ( ZM_WEB_USE_OBJECT_TAGS ) {
switch( $mimeType ) {
case "video/x-ms-asf" :
case "video/x-msvideo" :
case "video/mp4" :
{
if ( isWindows() )
{
?>
<object id="<?php echo $id ?>" width="<?php echo validNum($width) ?>" height="<?php echo validNum($height) ?>"
if ( isWindows() ) {
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'
classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902"
standby="Loading Microsoft Windows Media Player components..."
type="<?php echo $mimeType ?>">
<param name="FileName" value="<?php echo $src ?>"/>
type="'.$mimeType.'">
<param name="FileName" value="'.$src.'"/>
<param name="autoStart" value="1"/>
<param name="showControls" value="0"/>
<embed type="<?php echo $mimeType ?>"
<embed type="'.$mimeType.'"
pluginspage="http://www.microsoft.com/Windows/MediaPlayer/"
src="<?php echo $src ?>"
name="<?php echo validHtmlStr($title) ?>"
width="<?php echo validNum($width) ?>"
height="<?php echo validInt($height) ?>"
src="'.$src.'"
name="'.$title.'"
width="'.$width.'"
height="'.$height.'"
autostart="1"
showcontrols="0">
</embed>
</object>
<?php
$objectTag = true;
</object>';
}
break;
}
case "video/quicktime" :
{
?>
<object id="<?php echo $id ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
codebase="http://www.apple.com/qtactivex/qtplugin.cab"
type="<?php echo $mimeType ?>">
<param name="src" value="<?php echo $src ?>"/>
type="'.$mimeType.'">
<param name="src" value="'.$src.'"/>
<param name="autoplay" VALUE="true"/>
<param name="controller" VALUE="false"/>
<embed type="<?php echo $mimeType ?>"
src="<?php echo $src ?>"
<embed type="'.$mimeType.'"
src="'.$src.'"
pluginspage="http://www.apple.com/quicktime/download/"
name="<?php echo validHtmlStr($title) ?>"
width="<?php echo validInt($width) ?>"
height="<?php echo validInt($height) ?>"
name="'.$title.'" width="'.$width.'" height="'.$height.'"
autoplay="true"
controller="true">
</embed>
</object>
<?php
$objectTag = true;
break;
</object>';
}
case "application/x-shockwave-flash" :
{
?>
<object id="<?php echo $id ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
type="<?php echo $mimeType ?>">
<param name="movie" value="<?php echo $src ?>"/>
type="'.$mimeType.'">
<param name="movie" value="'.$src.'"/>
<param name="quality" value="high"/>
<param name="bgcolor" value="#ffffff"/>
<embed type="<?php echo $mimeType ?>"
<embed type="'.$mimeType.'"
pluginspage="http://www.macromedia.com/go/getflashplayer"
src="<?php echo $src ?>"
name="<?php echo validHtmlStr($title) ?>"
width="<?php echo validInt($width) ?>"
height="<?php echo validInt($height) ?>"
src="'.$src.'"
name="'.$title.'"
width="'.$width.'"
height="'.$height.'"
quality="high"
bgcolor="#ffffff">
</embed>
</object>
<?php
$objectTag = true;
break;
</object>';
}
}
}
if ( !$objectTag )
{
?>
<embed<?php echo isset($mimeType)?(' type="'.$mimeType.'"'):"" ?>
src="<?php echo $src ?>"
name="<?php echo validHtmlStr($title) ?>"
width="<?php echo validInt($width) ?>"
height="<?php echo validInt($height) ?>"
} # end switch
} # end if use object tags
return '<embed'. ( isset($mimeType)?(' type="'.$mimeType.'"'):'' ). '
src="'.$src.'"
name="'.$title.'"
width="'.$width.'"
height="'.$height.'"
autostart="1"
autoplay="1"
showcontrols="0"
controller="0">
</embed>
<?php
}
</embed>';
}
function outputImageStream( $id, $src, $width, $height, $title="" )
{
function outputImageStream( $id, $src, $width, $height, $title="" ) {
echo getImageStream( $id, $src, $width, $height, $title );
}
function getImageStream( $id, $src, $width, $height, $title="" ) {
if ( canStreamIframe() ) {
?>
<iframe id="<?php echo $id ?>" src="<?php echo $src ?>" alt="<?php echo validHtmlStr($title) ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"/>
<?php
return '<iframe id="'.$id.'" src="'.$src.'" alt="'. validHtmlStr($title) .'" width="'. validInt($width)." height=".validInt($height).'"/>';
} else {
?>
<img id="<?php echo $id ?>" src="<?php echo $src ?>" alt="<?php echo validHtmlStr($title) ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"/>
<?php
return '<img id="'.$id.'" src="'.$src.'" alt="'. validHtmlStr($title) .'" width="'. validInt($width) .'" height="'. validInt( $height ).'"/>';
}
}
@ -1685,7 +1668,11 @@ function getDiskPercent()
Error("disk_total_space returned false for " . ZM_DIR_EVENTS );
return 0;
}
$space = round(($total - disk_free_space(ZM_DIR_EVENTS)) / $total * 100);
$free = disk_free_space(ZM_DIR_EVENTS);
if ( ! $free ) {
Error("disk_free_space returned false for " . ZM_DIR_EVENTS );
}
$space = round(($total - $free) / $total * 100);
return( $space );
}
@ -2507,11 +2494,11 @@ function getStreamHTML( $monitor, $scale=100 ) {
//FIXME, the width and height of the image need to be scaled.
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
$streamSrc = $monitor->getStreamSrc( array( "mode=mpeg", "scale=".$scale, "bitrate=".ZM_WEB_VIDEO_BITRATE, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "format=".ZM_MPEG_LIVE_FORMAT ) );
outputVideoStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
return getVideoStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
} else if ( canStream() ) {
$streamSrc = $monitor->getStreamSrc( array( 'mode=jpeg', 'scale='.$scale, 'maxfps='.ZM_WEB_VIDEO_MAXFPS, 'buffer='.$monitor->StreamReplayBuffer() ) );
if ( canStreamNative() )
outputImageStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
return getImageStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
elseif ( canStreamApplet() )
outputHelperStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
} else {

View File

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

View File

@ -15,7 +15,6 @@
#menuBar1 {
width: 100%;
height: 1.5em;
padding: 3px 0;
text-align: center;
clear: both;
@ -41,7 +40,6 @@
#menuBar2 {
width: 100%;
height: 1.2em;
padding: 3px 0;
margin-bottom: 4px;
}
@ -57,6 +55,16 @@
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#imageFeed {
text-align: center;
}

View File

@ -15,12 +15,12 @@
#menuBar1 {
width: 100%;
height: 1.5em;
padding: 3px 0;
text-align: center;
clear: both;
}
#menuBar1 #nameControl {
float: left;
}
@ -41,7 +41,6 @@
#menuBar2 {
width: 100%;
height: 1.2em;
padding: 3px 0;
margin-bottom: 4px;
}
@ -56,6 +55,15 @@
float: right;
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#imageFeed {
text-align: center;

View File

@ -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 )
<div class="pantiltLabel"><?php echo translate('PanTilt') ?></div>
<div class="pantiltButtons">
<?php
$hasPan = $monitor->CanPan;
$hasTilt = $monitor->CanTilt;
$hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag;
$hasPan = $monitor->CanPan();
$hasTilt = $monitor->CanTilt();
$hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag();
?>
<div class="arrowBtn upLeftBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUpLeft'] ?>',event,-1,-1)"></div>
<div class="arrowBtn upBtn<?php echo $hasTilt?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUp'] ?>',event,0,-1)"></div>
@ -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 )
<!--<div><?php echo translate('Presets') ?></div>-->
<div>
<?php
for ( $i = 1; $i <= $monitor->NumPresets; $i++ )
for ( $i = 1; $i <= $monitor->NumPresets(); $i++ )
{
?><input type="button" class="ptzNumBtn" title="<?php echo isset($labels[$i])?$labels[$i]:"" ?>" value="<?php echo $i ?>" onclick="controlCmd('<?php echo $cmds['PresetGoto'] ?><?php echo $i ?>');"/><?php
if ( $i && (($i%$presetBreak) == 0) )

View File

@ -589,7 +589,6 @@ else if (document.layers) window.onload=start_slider;
function exportEventImagesMaster( $eids )
{
global $SLANG;
ob_start();
exportHeader( translate('Images').' Master' );
?>

View File

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

View File

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

View File

@ -54,7 +54,9 @@ if ( canEdit('Monitors') )
if ( $show_storage_areas ) { $columns += 1; }
echo $columns;
?>">
<input type="button" class="btn btn-default" value="<?php echo translate('AddNewMonitor'); ?>" onclick="createPopup( '?view=monitor', 'zmMonitor0', 'monitor' ); return( false );"></input>
<input type="button" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>
<!-- <?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?> -->
</td>
<?php
for ( $i = 0; $i < count($eventCounts); $i++ )

View File

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

View File

@ -66,13 +66,11 @@ if ( !empty($limit) && $nEvents > $limit )
$nEvents = $limit;
}
$pages = (int)ceil($nEvents/ZM_WEB_EVENTS_PER_PAGE);
if ( $pages > 1 ) {
if ( !empty($page) ) {
if ( !empty($page) ) {
if ( $page < 0 )
$page = 1;
if ( $page > $pages )
$page = $pages;
}
}
if ( !empty($page) ) {
$limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE);

View File

@ -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() );
?>
<body>
<div id="page">
<div id="header">
<div id="headerButtons">
<?php if ( ZM_RECORD_EVENT_STATS && $alarmFrame ) { echo makePopupLink( '?view=stats&amp;eid='.$event['Id'].'&amp;fid='.$frame['FrameId'], 'zmStats', 'stats', translate('Stats') ); } ?>
<?php if ( ZM_RECORD_EVENT_STATS && $alarmFrame ) { echo makePopupLink( '?view=stats&amp;eid='.$event['Id'].'&amp;fid='.$frame->FrameId(), 'zmStats', 'stats', translate('Stats') ); } ?>
<?php if ( canEdit( 'Events' ) ) { ?><a href="?view=none&amp;action=delete&amp;markEid=<?php echo $event['Id'] ?>"><?php echo translate('Delete') ?></a><?php } ?>
<a href="#" onclick="closeWindow(); return( false );"><?php echo translate('Close') ?></a>
</div>
<h2><?php echo translate('Frame') ?> <?php echo $event['Id']."-".$frame['FrameId']." (".$frame['Score'].")" ?></h2>
<h2><?php echo translate('Frame') ?> <?php echo $event['Id']."-".$frame->FrameId()." (".$frame->Score().")" ?></h2>
</div>
<div id="content">
<p id="image">
<?php if ( in_array($event['VideoWriter'],array("1","2")) ) { ?>
<img src="?view=image-ffmpeg&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame['FrameId'] ?>&scale=<?php echo $event['DefaultScale'] ?>" class="<?php echo $imageData['imageClass'] ?>">
<img src="?view=image-ffmpeg&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame->FrameId() ?>&scale=<?php echo $event['DefaultScale'] ?>" class="<?php echo $imageData['imageClass'] ?>">
<?php } else {
if ( $imageData['hasAnalImage'] ) { ?><a href="?view=frame&amp;eid=<?php echo $event['Id'] ?>&amp;fid=<?php echo $frame['FrameId'] ?>&amp;scale=<?php echo $scale ?>&amp;show=<?php echo $imageData['isAnalImage']?"capt":"anal" ?>"><?php } ?><img src="<?php echo viewImagePath( $imagePath ) ?>" width="<?php echo reScale( $event['Width'], $event['DefaultScale'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $event['DefaultScale'], $scale ) ?>" alt="<?php echo $frame['EventId']."-".$frame['FrameId'] ?>" class="<?php echo $imageData['imageClass'] ?>"/><?php if ( $imageData['hasAnalImage'] ) { ?></a><?php } ?>
if ( $imageData['hasAnalImage'] ) { ?><a href="?view=frame&amp;eid=<?php echo $event['Id'] ?>&amp;fid=<?php echo $frame->FrameId() ?>&amp;scale=<?php echo $scale ?>&amp;show=<?php echo $imageData['isAnalImage']?"capt":"anal" ?>"><?php } ?>
<img src="<?php echo $frame->getImageSrc() ?>" width="<?php echo reScale( $event['Width'], $event['DefaultScale'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $event['DefaultScale'], $scale ) ?>" alt="<?php echo $frame->EventId()."-".$frame->FrameId() ?>" class="<?php echo $imageData['imageClass'] ?>"/><?php if ( $imageData['hasAnalImage'] ) { ?></a><?php } ?>
<?php } ?>
</p>
<p id="controls">
<?php if ( $frame['FrameId'] > 1 ) { ?>
<?php if ( $frame->FrameId() > 1 ) { ?>
<a id="firstLink" href="?view=frame&amp;eid=<?php echo $event['Id'] ?>&amp;fid=<?php echo $firstFid ?>&amp;scale=<?php echo $scale ?>"><?php echo translate('First') ?></a>
<?php } if ( $frame['FrameId'] > 1 ) { ?>
<?php } if ( $frame->FrameId() > 1 ) { ?>
<a id="prevLink" href="?view=frame&amp;eid=<?php echo $event['Id'] ?>&amp;fid=<?php echo $prevFid ?>&amp;scale=<?php echo $scale ?>"><?php echo translate('Prev') ?></a>
<?php } if ( $frame['FrameId'] < $maxFid ) { ?>
<?php } if ( $frame->FrameId() < $maxFid ) { ?>
<a id="nextLink" href="?view=frame&amp;eid=<?php echo $event['Id'] ?>&amp;fid=<?php echo $nextFid ?>&amp;scale=<?php echo $scale ?>"><?php echo translate('Next') ?></a>
<?php } if ( $frame['FrameId'] < $maxFid ) { ?>
<?php } if ( $frame->FrameId() < $maxFid ) { ?>
<a id="lastLink" href="?view=frame&amp;eid=<?php echo $event['Id'] ?>&amp;fid=<?php echo $lastFid ?>&amp;scale=<?php echo $scale ?>"><?php echo translate('Last') ?></a>
<?php } ?>
</p>

View File

@ -205,14 +205,9 @@ $versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText'
<?php if ( canView( 'Stream' ) && $cycleCount > 1 ) {
$cycleGroup = isset($_COOKIE['zmGroup'])?$_COOKIE['zmGroup']:0;
?>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Montage <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><?php echo makePopupLink( '?view=cycle&amp;group='.$cycleGroup, 'zmCycle'.$cycleGroup, array( 'cycle', $cycleWidth, $cycleHeight ), translate('Cycle'), $running ) ?></li>
<li><?php echo makePopupLink( '?view=montage&amp;group='.$cycleGroup, 'zmMontage'.$cycleGroup, 'montage', translate('Montage'), $running ) ?></li>
<li><?php echo makePopupLink( '?view=montagereview&amp;group='.$cycleGroup, 'zmMontage'.$cycleGroup, 'montagereview', translate('Montage Review'), $running ) ?></li>
</ul>
</li>
<?php } ?>
</ul>

View File

@ -1,3 +1,6 @@
var jsTranslatedAddText;
var jsTranslatedCloneText;
function setButtonStates( element )
{
var form = element.form;
@ -12,21 +15,37 @@ function setButtonStates( element )
break;
}
}
else if ( form.elements[i].length )
}
$(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)
{
for( var j = 0, j_length = form.elements[i].length; j < j_length; j += 1 ) {
if ( form.elements[j].type == "checkbox" ) {
if ( form.elements[j].checked ) {
if ( checked++ > 1 )
// 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;
}
}
} // end foreach element in array
}
} // end foreach element in array
$(element).getParent( 'tr' ).toggleClass( 'highlight' );
form.editBtn.disabled = (checked!=1);
form.deleteBtn.disabled = (checked==0);
}
dupParam = (monitorId == -1 ) ? '': '&dupId='+monitorId;
createPopup( '?view=monitor'+dupParam, 'zmMonitor0','monitor' );
}
function editMonitor( element )
@ -66,6 +85,8 @@ function reloadWindow()
function initPage()
{
jsTranslatedAddText = translatedAddText;
jsTranslatedCloneText = translatedCloneText;
reloadWindow.periodical( consoleRefreshTimeout );
if ( showVersionPopup )
createPopup( '?view=version', 'zmVersion', 'version' );

View File

@ -26,7 +26,7 @@ elseif ( ZM_DYN_SHOW_DONATE_REMINDER )
?>
var showVersionPopup = <?php echo isset($showVersionPopup )?'true':'false' ?>;
var showDonatePopup = <?php echo isset($showDonatePopup )?'true':'false' ?>;
var translatedAddText = "<?php echo translate('AddNewMonitor') ?>";
var translatedCloneText = "<?php echo translate('CloneMonitor') ?>";

View File

@ -35,6 +35,7 @@ function Monitor( index, id, connKey )
if ( this.streamCmdTimer )
this.streamCmdTimer = clearTimeout( this.streamCmdTimer );
var stream = document.getElementById( "liveStream"+this.id );
if ( respObj.result == 'Ok' )
{
this.status = respObj.status;
@ -57,7 +58,6 @@ function Monitor( index, id, connKey )
this.setStateClass( $('monitor'+this.index), stateClass );
/*Stream could be an applet so can't use moo tools*/
var stream = document.getElementById( "liveStream"+this.id );
stream.className = stateClass;
var isAlarmed = ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT );
@ -90,6 +90,10 @@ function Monitor( index, id, connKey )
else
{
console.error( respObj.message );
// Try to reload the image stream.
if ( stream )
stream.src = stream.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
}
var streamCmdTimeout = statusRefreshTimeout;
if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT )

View File

@ -475,8 +475,211 @@ function drawZonePoints()
updateZoneImage();
}
function initPage()
//
// Imported from watch.js and modified for new zone edit view
//
var alarmState = STATE_IDLE;
var lastAlarmState = STATE_IDLE;
function setAlarmState( currentAlarmState ) {
alarmState = currentAlarmState;
var stateString = "Unknown";
var stateClass = "";
if ( alarmState == STATE_ALARM )
stateClass = "alarm";
else if ( alarmState == STATE_ALERT )
stateClass = "alert";
$('stateValue').set( 'text', stateStrings[alarmState] );
if ( stateClass )
$('stateValue').setProperty( 'class', stateClass );
else
$('stateValue').removeProperty( 'class' );
var isAlarmed = ( alarmState == STATE_ALARM || alarmState == STATE_ALERT );
var wasAlarmed = ( lastAlarmState == STATE_ALARM || lastAlarmState == STATE_ALERT );
var newAlarm = ( isAlarmed && !wasAlarmed );
var oldAlarm = ( !isAlarmed && wasAlarmed );
if ( newAlarm )
{
if ( SOUND_ON_ALARM )
{
// Enable the alarm sound
if ( !canPlayPauseAudio )
$('alarmSound').removeClass( 'hidden' );
else
$('MediaPlayer').Play();
}
}
if ( SOUND_ON_ALARM )
{
if ( oldAlarm )
{
// Disable alarm sound
if ( !canPlayPauseAudio )
$('alarmSound').addClass( 'hidden' );
else
$('MediaPlayer').Stop();
}
}
lastAlarmState = alarmState;
}
var streamCmdParms = "view=request&request=stream&connkey="+connKey;
var streamCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStreamCmdResponse } );
var streamCmdTimer = null;
var streamStatus;
function getStreamCmdResponse( respObj, respText ) {
watchdogOk("stream");
if ( streamCmdTimer )
streamCmdTimer = clearTimeout( streamCmdTimer );
if ( respObj.result == 'Ok' ) {
streamStatus = respObj.status;
$('fpsValue').set( 'text', streamStatus.fps );
setAlarmState( streamStatus.state );
var delayString = secsToTime( streamStatus.delay );
if ( streamStatus.paused == true )
{
streamCmdPause( false );
} else if ( streamStatus.delayed == true && streamStatus.rate == 1 ) {
streamCmdPlay( false );
}
} else {
checkStreamForErrors("getStreamCmdResponse",respObj);//log them
// Try to reload the image stream.
var streamImg = document.getElementById('liveStream');
if ( streamImg )
streamImg.src = streamImg.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
}
var streamCmdTimeout = statusRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT )
streamCmdTimeout = streamCmdTimeout/5;
streamCmdTimer = streamCmdQuery.delay( streamCmdTimeout );
}
var streamPause = false;
function streamCmdPauseToggle() {
if ( streamPause == true ) {
streamCmdPlay( true );
streamPause = false;
document.getElementById("pauseBtn").value = pauseString;
} else {
streamCmdPause( true );
streamPause = true;
document.getElementById("pauseBtn").value = playString;
}
}
function streamCmdPause( action ) {
if ( action )
streamCmdReq.send( streamCmdParms+"&command="+CMD_PAUSE );
}
function streamCmdPlay( action )
{
if ( action )
streamCmdReq.send( streamCmdParms+"&command="+CMD_PLAY );
}
function streamCmdStop( action ) {
if ( action )
streamCmdReq.send( streamCmdParms+"&command="+CMD_STOP );
}
function streamCmdQuery() {
streamCmdReq.send( streamCmdParms+"&command="+CMD_QUERY );
}
var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate";
var statusCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } );
var statusCmdTimer = null;
function getStatusCmdResponse( respObj, respText ) {
watchdogOk("status");
if ( statusCmdTimer )
statusCmdTimer = clearTimeout( statusCmdTimer );
if ( respObj.result == 'Ok' )
{
$('fpsValue').set( 'text', respObj.monitor.FrameRate );
setAlarmState( respObj.monitor.Status );
}
else
checkStreamForErrors("getStatusCmdResponse",respObj);
var statusCmdTimeout = statusRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT )
statusCmdTimeout = statusCmdTimeout/5;
statusCmdTimer = statusCmdQuery.delay( statusCmdTimeout );
}
function statusCmdQuery() {
statusCmdReq.send();
}
var tempImage = null;
function fetchImage( streamImage ) {
var now = new Date();
if ( !tempImage )
tempImage = new Element( 'img' );
tempImage.setProperty( 'src', streamSrc+'&'+now.getTime() );
$(streamImage).setProperty( 'src', tempImage.getProperty( 'src' ) );
}
function appletRefresh() {
if ( streamStatus && (!streamStatus.paused && !streamStatus.delayed) )
{
var streamImg = $('liveStream');
var parent = streamImg.getParent();
streamImg.dispose();
streamImg.inject( parent );
if ( appletRefreshTime )
appletRefresh.delay( appletRefreshTime*1000 );
}
else
{
appletRefresh.delay( 15*1000 ); //if we are paused or delayed check every 15 seconds if we are live yet...
}
}
var watchdogInactive = {
'stream': false,
'status': false
};
var watchdogFunctions = {
'stream': streamCmdQuery,
'status': statusCmdQuery
};
//Make sure the various refreshes are still taking effect
function watchdogCheck( type ) {
if ( watchdogInactive[type] ) {
console.log( "Detected streamWatch of type: " + type + " stopped, restarting" );
watchdogFunctions[type]();
watchdogInactive[type] = false;
} else {
watchdogInactive[type] = true;
}
}
function watchdogOk( type ) {
watchdogInactive[type] = false;
}
function initPage() {
var form = document.zoneForm;
//form.elements['newZone[Name]'].disabled = true;
@ -503,13 +706,37 @@ function initPage()
applyZoneType();
if ( form.elements['newZone[Units]'].value == 'Percent' )
{
if ( form.elements['newZone[Units]'].value == 'Percent' ) {
applyZoneUnits();
}
applyCheckMethod();
drawZonePoints();
//
// Imported from watch.js and modified for new zone edit view
//
if ( streamMode == "single" ) {
statusCmdTimer = statusCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
watchdogCheck.pass('status').periodical(statusRefreshTimeout*2);
} else {
streamCmdTimer = streamCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
watchdogCheck.pass('stream').periodical(statusRefreshTimeout*2);
}
if ( canStreamNative || streamMode == "single" ) {
var streamImg = $('imageFrame').getElement('img');
if ( !streamImg )
streamImg = $('imageFrame').getElement('object');
if ( streamMode == "single" ) {
streamImg.addEvent( 'click', fetchImage.pass( streamImg ) );
fetchImage.pass( streamImg ).periodical( imageRefreshTimeout );
}
}
if ( refreshApplet && appletRefreshTime )
appletRefresh.delay( appletRefreshTime*1000 );
}
window.addEvent( 'domready', initPage );

View File

@ -65,3 +65,55 @@ var minBlobAreaLtMaxString = '<?php echo addslashes(translate('MinBlobAreaLtMax'
var minBlobLtMinFilterString = '<?php echo addslashes(translate('MinBlobLtMinFilter')) ?>';
var minBlobsUnsetString = '<?php echo addslashes(translate('MinBlobsUnset')) ?>';
var minBlobsLtMaxString = '<?php echo addslashes(translate('MinBlobsLtMax')) ?>';
//
// Imported from watch.js.php and modified for new zone edit view
//
var STATE_IDLE = <?php echo STATE_IDLE ?>;
var STATE_PREALARM = <?php echo STATE_PREALARM ?>;
var STATE_ALARM = <?php echo STATE_ALARM ?>;
var STATE_ALERT = <?php echo STATE_ALERT ?>;
var STATE_TAPE = <?php echo STATE_TAPE ?>;
var stateStrings = new Array();
stateStrings[STATE_IDLE] = "<?php echo translate('Idle') ?>";
stateStrings[STATE_PREALARM] = "<?php echo translate('Idle') ?>";
stateStrings[STATE_ALARM] = "<?php echo translate('Alarm') ?>";
stateStrings[STATE_ALERT] = "<?php echo translate('Alert') ?>";
stateStrings[STATE_TAPE] = "<?php echo translate('Record') ?>";
var pauseString = "<?php echo translate('Pause') ?>";
var playString = "<?php echo translate('Play') ?>";
var deleteString = "<?php echo translate('Delete') ?>";
var CMD_PAUSE = <?php echo CMD_PAUSE ?>;
var CMD_PLAY = <?php echo CMD_PLAY ?>;
var CMD_STOP = <?php echo CMD_STOP ?>;
var CMD_QUERY = <?php echo CMD_QUERY ?>;
var SCALE_BASE = <?php echo SCALE_BASE ?>;
var SOUND_ON_ALARM = <?php echo ZM_WEB_SOUND_ON_ALARM ?>;
var streamMode = "<?php echo $streamMode ?>";
var connKey = '<?php echo $connkey ?>';
var monitorId = <?php echo $monitor->Id() ?>;
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
var streamSrc = "<?php echo preg_replace( '/&amp;/', '&', $streamSrc ) ?>";
var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
var imageRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_IMAGE ?>;
var canEditMonitors = <?php echo canEdit( 'Monitors' )?'true':'false' ?>;
var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>;
var canPlayPauseAudio = Browser.ie;
var refreshApplet = <?php echo (canStreamApplet() && $streamMode == "jpeg")?'true':'false' ?>;
var appletRefreshTime = <?php echo ZM_RELOAD_CAMBOZOLA ?>;

View File

@ -0,0 +1,8 @@
var streamCmdParms = "view=request&request=stream&connkey="+connKey;
var streamCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel' } );
function streamCmdQuit( action ) {
if ( action )
streamCmdReq.send( streamCmdParms+"&command="+CMD_QUIT );
}

View File

@ -0,0 +1,4 @@
var connKey = '<?php echo $connkey ?>';
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
var CMD_QUIT = <?php echo CMD_QUIT ?>;

View File

@ -58,6 +58,13 @@ if ( ! empty($_REQUEST['mid']) ) {
} else {
$nextId = getTableAutoInc( 'Monitors' );
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,
@ -131,7 +138,8 @@ if ( ! empty($_REQUEST['mid']) ) {
'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) );
?>
<body>
<div id="page">
<div id="header">
<div id="page">
<div id="header">
<?php if ( canEdit( 'Monitors' ) ) { ?>
<?php if ( isset ($_REQUEST['dupId'])) { ?>
<div class="alert alert-info">
Configuration cloned from Monitor: <?php echo $clonedName ?>
</div>
<?php } ?>
<div id="headerButtons">
<a href="#" onclick="createPopup( '?view=monitorprobe&amp;mid=<?php echo $monitor->Id ?>', 'zmMonitorProbe<?php echo $monitor->Id ?>', 'monitorprobe' ); return( false );"><?php echo translate('Probe') ?></a>
<?php
if ( ZM_HAS_ONVIF ) {
?>
<?php if ( ZM_HAS_ONVIF ) { ?>
<a href="#" onclick="createPopup( '?view=onvifprobe&amp;mid=<?php echo $monitor->Id ?>', 'zmOnvifProbe<?php echo $monitor->Id ?>', 'onvifprobe' ); return( false );"><?php echo translate('OnvifProbe') ?></a>
<?php
}
?>
<?php } ?>
<a href="#" onclick="createPopup( '?view=monitorpreset&amp;mid=<?php echo $monitor->Id ?>', 'zmMonitorPreset<?php echo $monitor->Id ?>', 'monitorpreset' ); return( false );"><?php echo translate('Presets') ?></a>
</div>
<?php
}
?>
<?php } ?>
<h2><?php echo translate('Monitor') ?> - <?php echo validHtmlStr($monitor->Name) ?><?php if ( !empty($monitor->Id) ) { ?> (<?php echo $monitor->Id ?>)<?php } ?></h2>
</div>
<div id="content">
@ -717,21 +725,21 @@ switch ( $tab )
</td>
</tr>
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($monitor->AnalysisFPS) ?>" size="6"/></td></tr>
<?php
if ( $monitor->Type != "Local" && $monitor->Type != "File" )
{
?>
<tr><td><?php echo translate('MaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[MaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS) ?>" size="5"/><span id="newMonitor[MaxFPS]" style="color:red"></span></td></tr>
<tr><td><?php echo translate('AlarmMaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[AlarmMaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS) ?>" size="5"/><span id="newMonitor[AlarmMaxFPS]" style="color:red"></span></td></tr>
<?php
} else {
?>
<?php if ( $monitor->Type != "Local" && $monitor->Type != "File" ) { ?>
<tr>
<td><?php echo translate('MaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
<td><input type="text" onclick="document.getElementById('newMonitor[MaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS) ?>" size="5"/><span id="newMonitor[MaxFPS]" style="color:red"></span></td>
</tr>
<tr>
<td><?php echo translate('AlarmMaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
<td><input type="text" onclick="document.getElementById('newMonitor[AlarmMaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS) ?>" size="5"/><span id="newMonitor[AlarmMaxFPS]" style="color:red"></span></td>
</tr>
<?php } else { ?>
<tr><td><?php echo translate('MaximumFPS') ?></td><td><input type="text" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS) ?>" size="5"/></td></tr>
<tr><td><?php echo translate('AlarmMaximumFPS') ?></td><td><input type="text" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS) ?>" size="5"/></td></tr>
<?php
}
if ( ZM_FAST_IMAGE_BLENDS )
{
if ( ZM_FAST_IMAGE_BLENDS ) {
?>
<tr><td><?php echo translate('RefImageBlendPct') ?></td><td><select name="newMonitor[RefBlendPerc]"><?php foreach ( $fastblendopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->RefBlendPerc ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('AlmRefImageBlendPct') ?></td><td><select name="newMonitor[AlarmRefBlendPerc]"><?php foreach ( $fastblendopts_alarm as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->AlarmRefBlendPerc ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
@ -970,13 +978,14 @@ switch ( $tab )
}
}
?>
</tbody>
</table>
<div id="contentButtons">
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
</div>
</form>
</div>
</div>
</tbody>
</table>
<div id="contentButtons">
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
</div>
</form>
</div>
</div>
</body>
</html>

View File

@ -115,7 +115,10 @@ if ( canEdit( 'Monitors' ) )
if ( canEdit( 'Monitors' ) )
{
?>
<div id="forceCancelAlarm"><a id="forceAlarmLink" href="#" onclick="cmdForceAlarm()" class="hidden"><?php echo translate('ForceAlarm') ?></a><a id="cancelAlarmLink" href="#" onclick="cmdCancelForcedAlarm()" class="hidden"><?php echo translate('CancelForcedAlarm') ?></a></div>
<div id="forceCancelAlarm">
<a id="forceAlarmLink" href="#" onclick="cmdForceAlarm();"><?php echo translate('ForceAlarm') ?></a>
<a id="cancelAlarmLink" href="#" onclick="cmdCancelForcedAlarm();" class="hidden"><?php echo translate('CancelForcedAlarm') ?></a>
</div>
<?php
}
?>

View File

@ -117,6 +117,11 @@ $newZone['Area'] = getPolyArea( $newZone['Points'] );
$selfIntersecting = isSelfIntersecting( $newZone['Points'] );
$focusWindow = true;
$connkey = generateConnKey();
$streamSrc = '';
$streamMode = '';
# Have to do this here, because the .js.php references somethings figured out when generating the streamHTML
$StreamHTML = getStreamHTML( $monitor, $scale );
xhtmlHeaders(__FILE__, translate('Zone') );
?>
@ -210,13 +215,14 @@ xhtmlHeaders(__FILE__, translate('Zone') );
<div id="definitionPanel">
<div id="imagePanel">
<div id="imageFrame" style="width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px;">
<?php echo getStreamHTML( $monitor, $scale ); ?>
<?php $StreamHTML; ?>
<svg id="zoneSVG" class="zones" style="width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px;margin-top: -<?php echo $monitor->Height ?>px;background: none;">
<polygon id="zonePoly" points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type'] ?>"/>
Sorry, your browser does not support inline SVG
</svg>
</div>
</div>
<div id="monitorState"><?php echo translate('State') ?>:&nbsp;<span id="stateValue"></span>&nbsp;-&nbsp;<span id="fpsValue"></span>&nbsp;fps</div>
<table id="zonePoints" cellspacing="0">
<tbody>
<tr>
@ -265,7 +271,7 @@ for ( $i = 0; $i < $pointCols; $i++ )
</tr>
</tbody>
</table>
<input type="submit" id="submitBtn" name="submitBtn" value="<?php echo translate('Save') ?>" onclick="return saveChanges( this )"<?php if (!canEdit( 'Monitors' ) || (false && $selfIntersecting)) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
<input id="pauseBtn" type="button" value="<?php echo translate('Pause') ?>" onclick="streamCmdPauseToggle()"/><input type="submit" id="submitBtn" name="submitBtn" value="<?php echo translate('Save') ?>" onclick="return saveChanges( this )"<?php if (!canEdit( 'Monitors' ) || (false && $selfIntersecting)) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="refreshParentWindow(); closeWindow();"/>
</div>
</form>
</div>

View File

@ -37,6 +37,8 @@ foreach( dbFetchAll( 'select * from Zones where MonitorId = ? order by Area desc
}
}
$connkey = generateConnKey();
xhtmlHeaders(__FILE__, translate('Zones') );
?>
<body>
@ -51,7 +53,7 @@ xhtmlHeaders(__FILE__, translate('Zones') );
<?php
foreach( array_reverse($zones) as $zone ) {
?>
<polygon points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type']?>" onclick="createPopup( '?view=zone&amp;mid=<?php echo $mid ?>&amp;zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width ?>, <?php echo $monitor->Height ?> ); return( false );"/>
<polygon points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type']?>" onclick="streamCmdQuit( true ); createPopup( '?view=zone&amp;mid=<?php echo $mid ?>&amp;zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width ?>, <?php echo $monitor->Height ?> ); return( false );"/>
<?php
} // end foreach zone
?>
@ -76,7 +78,7 @@ foreach( $zones as $zone )
{
?>
<tr>
<td class="colName"><a href="#" onclick="createPopup( '?view=zone&amp;mid=<?php echo $mid ?>&amp;zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width() ?>, <?php echo $monitor->Height() ?> ); return( false );"><?php echo $zone['Name'] ?></a></td>
<td class="colName"><a href="#" onclick="streamCmdQuit( true ); createPopup( '?view=zone&amp;mid=<?php echo $mid ?>&amp;zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width() ?>, <?php echo $monitor->Height() ?> ); return( false );"><?php echo $zone['Name'] ?></a></td>
<td class="colType"><?php echo $zone['Type'] ?></td>
<td class="colUnits"><?php echo $zone['Area'] ?>&nbsp;/&nbsp;<?php echo sprintf( "%.2f", ($zone['Area']*100)/($monitor->Width()*$monitor->Height()) ) ?></td>
<td class="colMark"><input type="checkbox" name="markZids[]" value="<?php echo $zone['Id'] ?>" onclick="configureDeleteButton( this );"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/></td>

View File

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