2003-03-26 19:57:29 +08:00
//
// ZoneMinder Monitor Class Implementation, $Date$, $Revision$
// Copyright (C) 2003 Philip Coombes
//
// 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.
//
# include <sys/ipc.h>
# include <sys/shm.h>
# include "zm.h"
# include "zm_db.h"
2004-03-04 23:05:54 +08:00
# include "zm_mpeg.h"
2003-03-26 19:57:29 +08:00
# include "zm_monitor.h"
# include "zm_local_camera.h"
# include "zm_remote_camera.h"
2004-02-16 03:53:10 +08:00
bool Monitor : : initialised = false ;
bool Monitor : : record_event_stats ;
bool Monitor : : record_diag_images ;
bool Monitor : : opt_adaptive_skip ;
bool Monitor : : create_analysis_images ;
bool Monitor : : blend_alarmed_images ;
2004-02-16 04:07:16 +08:00
bool Monitor : : timestamp_on_capture ;
2004-03-05 18:23:01 +08:00
int Monitor : : bulk_frame_interval ;
2004-02-16 03:53:10 +08:00
2003-09-23 17:52:45 +08:00
Monitor : : Monitor (
int p_id ,
char * p_name ,
int p_function ,
int p_device ,
int p_channel ,
int p_format ,
int p_width ,
int p_height ,
int p_palette ,
int p_orientation ,
char * p_label_format ,
const Coord & p_label_coord ,
int p_image_buffer_count ,
int p_warmup_count ,
int p_pre_event_count ,
int p_post_event_count ,
int p_section_length ,
2003-10-08 22:49:26 +08:00
int p_frame_skip ,
2003-09-23 17:52:45 +08:00
int p_capture_delay ,
int p_fps_report_interval ,
int p_ref_blend_perc ,
Purpose p_purpose ,
int p_n_zones ,
Zone * p_zones [ ]
) : id ( p_id ) ,
function ( ( Function ) p_function ) ,
width ( p_width ) ,
height ( p_height ) ,
orientation ( ( Orientation ) p_orientation ) ,
label_coord ( p_label_coord ) ,
image_buffer_count ( p_image_buffer_count ) ,
warmup_count ( p_warmup_count ) ,
pre_event_count ( p_pre_event_count ) ,
post_event_count ( p_post_event_count ) ,
section_length ( p_section_length ) ,
2003-10-08 22:49:26 +08:00
frame_skip ( p_frame_skip ) ,
2003-09-23 17:52:45 +08:00
capture_delay ( p_capture_delay ) ,
fps_report_interval ( p_fps_report_interval ) ,
ref_blend_perc ( p_ref_blend_perc ) ,
image ( width , height , ( p_palette = = VIDEO_PALETTE_GREY ? 1 : 3 ) ) ,
ref_image ( width , height , ( p_palette = = VIDEO_PALETTE_GREY ? 1 : 3 ) ) ,
purpose ( p_purpose ) ,
n_zones ( p_n_zones ) ,
zones ( p_zones )
2003-03-26 19:57:29 +08:00
{
name = new char [ strlen ( p_name ) + 1 ] ;
strcpy ( name , p_name ) ;
2004-04-20 00:02:17 +08:00
strncpy ( label_format , p_label_format , sizeof ( label_format ) ) ;
2003-03-26 19:57:29 +08:00
2003-09-23 17:52:45 +08:00
camera = new LocalCamera ( p_device , p_channel , p_format , ( p_orientation % 2 ) ? width : height , ( orientation % 2 ) ? height : width , p_palette , purpose = = CAPTURE ) ;
2003-03-26 19:57:29 +08:00
2004-02-16 03:53:10 +08:00
Setup ( ) ;
2003-06-12 22:29:54 +08:00
}
2003-03-26 19:57:29 +08:00
2003-09-23 17:52:45 +08:00
Monitor : : Monitor (
int p_id ,
char * p_name ,
int p_function ,
const char * p_host ,
const char * p_port ,
const char * p_path ,
int p_width ,
int p_height ,
int p_palette ,
int p_orientation ,
char * p_label_format ,
const Coord & p_label_coord ,
int p_image_buffer_count ,
int p_warmup_count ,
int p_pre_event_count ,
int p_post_event_count ,
int p_section_length ,
2003-10-08 22:49:26 +08:00
int p_frame_skip ,
2003-09-23 17:52:45 +08:00
int p_capture_delay ,
int p_fps_report_interval ,
int p_ref_blend_perc ,
Purpose p_purpose ,
int p_n_zones ,
Zone * p_zones [ ]
) : id ( p_id ) ,
function ( ( Function ) p_function ) ,
width ( p_width ) ,
height ( p_height ) ,
orientation ( ( Orientation ) p_orientation ) ,
label_coord ( p_label_coord ) ,
image_buffer_count ( p_image_buffer_count ) ,
warmup_count ( p_warmup_count ) ,
pre_event_count ( p_pre_event_count ) ,
post_event_count ( p_post_event_count ) ,
section_length ( p_section_length ) ,
2003-10-08 22:49:26 +08:00
frame_skip ( p_frame_skip ) ,
2003-09-23 17:52:45 +08:00
capture_delay ( p_capture_delay ) ,
fps_report_interval ( p_fps_report_interval ) ,
ref_blend_perc ( p_ref_blend_perc ) ,
image ( width , height , ( p_palette = = VIDEO_PALETTE_GREY ? 1 : 3 ) ) ,
ref_image ( width , height , ( p_palette = = VIDEO_PALETTE_GREY ? 1 : 3 ) ) ,
purpose ( p_purpose ) ,
n_zones ( p_n_zones ) ,
zones ( p_zones )
2003-06-12 22:29:54 +08:00
{
name = new char [ strlen ( p_name ) + 1 ] ;
strcpy ( name , p_name ) ;
2003-03-26 19:57:29 +08:00
2004-04-20 00:02:17 +08:00
strncpy ( label_format , p_label_format , sizeof ( label_format ) ) ;
2003-03-26 19:57:29 +08:00
2003-09-23 17:52:45 +08:00
camera = new RemoteCamera ( p_host , p_port , p_path , ( p_orientation % 2 ) ? width : height , ( orientation % 2 ) ? height : width , p_palette , purpose = = CAPTURE ) ;
2003-03-26 19:57:29 +08:00
2004-02-16 03:53:10 +08:00
Setup ( ) ;
2003-06-12 22:29:54 +08:00
}
2003-03-26 19:57:29 +08:00
2003-06-12 22:29:54 +08:00
Monitor : : ~ Monitor ( )
{
2003-10-08 20:54:35 +08:00
if ( event )
{
if ( function = = RECORD | | function = = MOCORD )
{
gettimeofday ( & ( event - > EndTime ( ) ) , & dummy_tz ) ;
}
delete event ;
}
2003-06-12 22:29:54 +08:00
delete [ ] image_buffer ;
2003-03-26 19:57:29 +08:00
2003-12-12 00:41:20 +08:00
if ( purpose = = ANALYSIS )
{
2004-02-06 01:26:58 +08:00
shared_data - > state = state = IDLE ;
2003-12-12 00:41:20 +08:00
shared_data - > last_read_index = image_buffer_count ;
}
2003-06-12 22:29:54 +08:00
struct shmid_ds shm_data ;
if ( shmctl ( shmid , IPC_STAT , & shm_data ) )
2003-03-26 19:57:29 +08:00
{
2003-06-12 22:29:54 +08:00
Error ( ( " Can't shmctl: %s " , strerror ( errno ) ) ) ;
exit ( - 1 ) ;
2003-03-26 19:57:29 +08:00
}
2003-06-12 22:29:54 +08:00
if ( shm_data . shm_nattch < = 1 )
{
if ( shmctl ( shmid , IPC_RMID , 0 ) )
2003-03-26 19:57:29 +08:00
{
2003-06-12 22:29:54 +08:00
Error ( ( " Can't shmctl: %s " , strerror ( errno ) ) ) ;
exit ( - 1 ) ;
2003-03-26 19:57:29 +08:00
}
}
}
2004-02-16 03:53:10 +08:00
void Monitor : : Setup ( )
2003-03-26 19:57:29 +08:00
{
2004-02-16 03:53:10 +08:00
if ( ! initialised )
Initialise ( ) ;
2003-03-26 19:57:29 +08:00
fps = 0.0 ;
event_count = 0 ;
image_count = 0 ;
first_alarm_count = 0 ;
last_alarm_count = 0 ;
state = IDLE ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " monitor purpose=%d " , purpose ) ) ;
2003-06-12 22:29:54 +08:00
int shared_data_size = sizeof ( SharedData ) + ( image_buffer_count * sizeof ( time_t ) ) + ( image_buffer_count * camera - > ImageSize ( ) ) ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " shm.size=%d " , shared_data_size ) ) ;
2003-07-06 04:40:53 +08:00
shmid = shmget ( ( int ) config . Item ( ZM_SHM_KEY ) | id , shared_data_size , IPC_CREAT | 0700 ) ;
2003-03-26 19:57:29 +08:00
if ( shmid < 0 )
{
2003-03-27 06:12:25 +08:00
Error ( ( " Can't shmget: %s " , strerror ( errno ) ) ) ;
2003-03-26 19:57:29 +08:00
exit ( - 1 ) ;
}
unsigned char * shm_ptr = ( unsigned char * ) shmat ( shmid , 0 , 0 ) ;
2003-06-12 22:29:54 +08:00
shared_data = ( SharedData * ) shm_ptr ;
if ( shared_data < 0 )
2003-03-26 19:57:29 +08:00
{
2003-03-27 06:12:25 +08:00
Error ( ( " Can't shmat: %s " , strerror ( errno ) ) ) ;
2003-03-26 19:57:29 +08:00
exit ( - 1 ) ;
}
2003-09-23 17:52:45 +08:00
if ( purpose = = CAPTURE )
2003-03-26 19:57:29 +08:00
{
2003-06-12 22:29:54 +08:00
memset ( shared_data , 0 , shared_data_size ) ;
shared_data - > valid = true ;
shared_data - > state = IDLE ;
2003-06-25 17:47:09 +08:00
shared_data - > force_state = FORCE_NEUTRAL ;
2003-06-12 22:29:54 +08:00
shared_data - > last_write_index = image_buffer_count ;
shared_data - > last_read_index = image_buffer_count ;
2003-07-06 04:40:53 +08:00
shared_data - > last_image_time = 0 ;
2003-06-12 22:29:54 +08:00
shared_data - > last_event = 0 ;
2003-06-25 17:47:09 +08:00
shared_data - > action = ( Action ) 0 ;
shared_data - > brightness = - 1 ;
shared_data - > hue = - 1 ;
shared_data - > colour = - 1 ;
shared_data - > contrast = - 1 ;
2003-06-12 22:29:54 +08:00
}
if ( ! shared_data - > valid )
{
Error ( ( " Shared memory not initialised by capture daemon " ) ) ;
exit ( - 1 ) ;
2003-03-26 19:57:29 +08:00
}
2003-06-12 22:29:54 +08:00
struct timeval * shared_timestamps = ( struct timeval * ) ( shm_ptr + sizeof ( SharedData ) ) ;
unsigned char * shared_images = ( unsigned char * ) ( shm_ptr + sizeof ( SharedData ) + ( image_buffer_count * sizeof ( struct timeval ) ) ) ;
2003-03-26 19:57:29 +08:00
image_buffer = new Snapshot [ image_buffer_count ] ;
for ( int i = 0 ; i < image_buffer_count ; i + + )
{
2003-06-12 22:29:54 +08:00
image_buffer [ i ] . timestamp = & ( shared_timestamps [ i ] ) ;
image_buffer [ i ] . image = new Image ( width , height , camera - > Colours ( ) , & ( shared_images [ i * camera - > ImageSize ( ) ] ) ) ;
2003-03-26 19:57:29 +08:00
}
if ( ! n_zones )
{
n_zones = 1 ;
zones = new Zone * [ 1 ] ;
2004-02-16 04:02:41 +08:00
zones [ 0 ] = new Zone ( this , 0 , " All " , Zone : : ACTIVE , Box ( width , height ) , RGB_RED , Zone : : BLOBS ) ;
2003-03-26 19:57:29 +08:00
}
start_time = last_fps_time = time ( 0 ) ;
event = 0 ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Monitor %s has function %d " , name , function ) ) ;
Debug ( 1 , ( " Monitor %s LBF = '%s', LBX = %d, LBY = %d " , name , label_format , label_coord . X ( ) , label_coord . Y ( ) ) ) ;
Debug ( 1 , ( " Monitor %s IBC = %d, WUC = %d, pEC = %d, PEC = %d, FRI = %d, RBP = %d " , name , image_buffer_count , warmup_count , pre_event_count , post_event_count , fps_report_interval , ref_blend_perc ) ) ;
2003-03-26 19:57:29 +08:00
2003-09-23 17:52:45 +08:00
if ( purpose = = ANALYSIS )
2003-03-26 19:57:29 +08:00
{
static char path [ PATH_MAX ] ;
2004-04-20 00:02:17 +08:00
strncpy ( path , ( const char * ) config . Item ( ZM_DIR_EVENTS ) , sizeof ( path ) ) ;
2003-03-26 19:57:29 +08:00
struct stat statbuf ;
errno = 0 ;
stat ( path , & statbuf ) ;
if ( errno = = ENOENT | | errno = = ENOTDIR )
{
if ( mkdir ( path , 0755 ) )
{
Error ( ( " Can't make %s: %s " , path , strerror ( errno ) ) ) ;
}
}
2004-04-20 00:02:17 +08:00
snprintf ( path , sizeof ( path ) , " %s/%s " , ( const char * ) config . Item ( ZM_DIR_EVENTS ) , name ) ;
2003-03-26 19:57:29 +08:00
errno = 0 ;
stat ( path , & statbuf ) ;
if ( errno = = ENOENT | | errno = = ENOTDIR )
{
if ( mkdir ( path , 0755 ) )
{
Error ( ( " Can't make %s: %s " , path , strerror ( errno ) ) ) ;
}
}
2003-06-12 22:29:54 +08:00
while ( shared_data - > last_write_index = = image_buffer_count )
2003-03-26 19:57:29 +08:00
{
2003-06-12 22:29:54 +08:00
Warning ( ( " Waiting for capture daemon " ) ) ;
sleep ( 1 ) ;
2003-03-26 19:57:29 +08:00
}
2003-06-12 22:29:54 +08:00
ref_image . Assign ( width , height , camera - > Colours ( ) , image_buffer [ shared_data - > last_write_index ] . image - > Buffer ( ) ) ;
2003-03-26 19:57:29 +08:00
}
}
void Monitor : : AddZones ( int p_n_zones , Zone * p_zones [ ] )
{
n_zones = p_n_zones ;
zones = p_zones ;
}
Monitor : : State Monitor : : GetState ( ) const
{
2003-06-12 22:29:54 +08:00
return ( shared_data - > state ) ;
2003-03-26 19:57:29 +08:00
}
2004-02-18 23:35:51 +08:00
int Monitor : : GetImage ( int index , int scale ) const
2003-03-26 19:57:29 +08:00
{
if ( index < 0 | | index > image_buffer_count )
{
2003-06-12 22:29:54 +08:00
index = shared_data - > last_write_index ;
2003-03-26 19:57:29 +08:00
}
Snapshot * snap = & image_buffer [ index ] ;
2004-02-18 23:35:51 +08:00
Image snap_image ( * ( snap - > image ) ) ;
if ( scale ! = 100 )
{
snap_image . Scale ( scale ) ;
}
2003-03-26 19:57:29 +08:00
2004-02-16 04:07:16 +08:00
static char filename [ PATH_MAX ] ;
2004-04-20 00:02:17 +08:00
snprintf ( filename , sizeof ( filename ) , " %s.jpg " , name ) ;
2004-02-16 04:07:16 +08:00
if ( ! timestamp_on_capture )
{
2004-02-18 23:35:51 +08:00
TimestampImage ( & snap_image , snap - > timestamp - > tv_sec ) ;
2004-02-16 04:07:16 +08:00
}
2004-02-18 23:35:51 +08:00
snap_image . WriteJpeg ( filename ) ;
2003-03-26 19:57:29 +08:00
return ( 0 ) ;
}
struct timeval Monitor : : GetTimestamp ( int index ) const
{
if ( index < 0 | | index > image_buffer_count )
{
2003-06-12 22:29:54 +08:00
index = shared_data - > last_write_index ;
2003-03-26 19:57:29 +08:00
}
2003-06-12 22:29:54 +08:00
2003-03-26 19:57:29 +08:00
Snapshot * snap = & image_buffer [ index ] ;
return ( * ( snap - > timestamp ) ) ;
}
unsigned int Monitor : : GetLastReadIndex ( ) const
{
2003-06-12 22:29:54 +08:00
return ( shared_data - > last_read_index ) ;
2003-03-26 19:57:29 +08:00
}
unsigned int Monitor : : GetLastWriteIndex ( ) const
{
2003-06-12 22:29:54 +08:00
return ( shared_data - > last_write_index ) ;
2003-03-26 19:57:29 +08:00
}
unsigned int Monitor : : GetLastEvent ( ) const
{
2003-06-12 22:29:54 +08:00
return ( shared_data - > last_event ) ;
2003-03-26 19:57:29 +08:00
}
double Monitor : : GetFPS ( ) const
{
2003-06-12 22:29:54 +08:00
int index1 = shared_data - > last_write_index ;
2004-03-04 23:05:54 +08:00
Snapshot * snap1 = & image_buffer [ index1 ] ;
if ( ! snap1 - > timestamp | | ! snap1 - > timestamp - > tv_sec )
{
return ( 0.0 ) ;
}
time_t time1 = snap1 - > timestamp - > tv_sec ;
2003-03-26 19:57:29 +08:00
2004-03-04 23:05:54 +08:00
int image_count = image_buffer_count ;
int index2 = ( index1 + 1 ) % image_buffer_count ;
2003-03-26 19:57:29 +08:00
Snapshot * snap2 = & image_buffer [ index2 ] ;
2004-03-04 23:05:54 +08:00
while ( ! snap2 - > timestamp | | ! snap2 - > timestamp - > tv_sec | | time1 = = snap2 - > timestamp - > tv_sec )
{
if ( index1 = = index2 )
{
return ( 0.0 ) ;
}
index2 = ( index2 + 1 ) % image_buffer_count ;
snap2 = & image_buffer [ index2 ] ;
image_count - - ;
}
2003-03-26 19:57:29 +08:00
time_t time2 = snap2 - > timestamp - > tv_sec ;
2004-03-04 23:05:54 +08:00
double curr_fps = double ( image_count ) / ( time1 - time2 ) ;
2003-03-26 19:57:29 +08:00
2004-01-15 05:26:47 +08:00
return ( curr_fps ) ;
2003-03-26 19:57:29 +08:00
}
2003-03-26 21:18:26 +08:00
void Monitor : : ForceAlarmOn ( )
2003-03-26 19:57:29 +08:00
{
2003-06-12 22:29:54 +08:00
shared_data - > force_state = FORCE_ON ;
2003-03-26 19:57:29 +08:00
}
2003-03-26 21:18:26 +08:00
void Monitor : : ForceAlarmOff ( )
2003-03-26 19:57:29 +08:00
{
2003-06-12 22:29:54 +08:00
shared_data - > force_state = FORCE_OFF ;
2003-03-26 21:18:26 +08:00
}
void Monitor : : CancelForced ( )
{
2003-06-12 22:29:54 +08:00
shared_data - > force_state = FORCE_NEUTRAL ;
2003-03-26 19:57:29 +08:00
}
2003-06-25 17:47:09 +08:00
int Monitor : : Brightness ( int p_brightness )
{
2003-09-23 17:52:45 +08:00
if ( purpose ! = CAPTURE )
2003-06-25 17:47:09 +08:00
{
if ( p_brightness > = 0 )
{
shared_data - > brightness = p_brightness ;
shared_data - > action | = SET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & SET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
return ( shared_data - > brightness ) ;
}
return ( camera - > Brightness ( p_brightness ) ) ;
}
int Monitor : : Contrast ( int p_contrast )
{
2003-09-23 17:52:45 +08:00
if ( purpose ! = CAPTURE )
2003-06-25 17:47:09 +08:00
{
if ( p_contrast > = 0 )
{
shared_data - > contrast = p_contrast ;
shared_data - > action | = SET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & SET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
return ( shared_data - > contrast ) ;
}
return ( camera - > Contrast ( p_contrast ) ) ;
}
int Monitor : : Hue ( int p_hue )
{
2003-09-23 17:52:45 +08:00
if ( purpose ! = CAPTURE )
2003-06-25 17:47:09 +08:00
{
if ( p_hue > = 0 )
{
shared_data - > hue = p_hue ;
shared_data - > action | = SET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & SET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
return ( shared_data - > hue ) ;
}
return ( camera - > Hue ( p_hue ) ) ;
}
int Monitor : : Colour ( int p_colour )
{
2003-09-23 17:52:45 +08:00
if ( purpose ! = CAPTURE )
2003-06-25 17:47:09 +08:00
{
if ( p_colour > = 0 )
{
shared_data - > colour = p_colour ;
shared_data - > action | = SET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & SET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
else
return ( - 1 ) ;
}
}
return ( shared_data - > colour ) ;
}
return ( camera - > Colour ( p_colour ) ) ;
}
2003-03-26 19:57:29 +08:00
void Monitor : : DumpZoneImage ( )
{
2003-06-12 22:29:54 +08:00
int index = shared_data - > last_write_index ;
2003-03-26 19:57:29 +08:00
Snapshot * snap = & image_buffer [ index ] ;
2004-01-15 05:26:47 +08:00
Image * snap_image = snap - > image ;
2003-03-26 19:57:29 +08:00
2004-01-15 05:26:47 +08:00
Image zone_image ( * snap_image ) ;
2003-03-26 19:57:29 +08:00
zone_image . Colourise ( ) ;
for ( int i = 0 ; i < n_zones ; i + + )
{
Rgb colour ;
if ( zones [ i ] - > IsActive ( ) )
{
colour = RGB_RED ;
}
else if ( zones [ i ] - > IsInclusive ( ) )
{
colour = RGB_GREEN ;
}
else if ( zones [ i ] - > IsExclusive ( ) )
{
colour = RGB_BLUE ;
}
2003-07-07 19:20:06 +08:00
else if ( zones [ i ] - > IsPreclusive ( ) )
{
colour = RGB_BLACK ;
}
2003-03-26 19:57:29 +08:00
else
{
colour = RGB_WHITE ;
}
zone_image . Hatch ( colour , & ( zones [ i ] - > Limits ( ) ) ) ;
}
2004-02-16 04:07:16 +08:00
static char filename [ PATH_MAX ] ;
2004-04-20 00:02:17 +08:00
snprintf ( filename , sizeof ( filename ) , " %s-Zones.jpg " , name ) ;
2003-03-26 19:57:29 +08:00
zone_image . WriteJpeg ( filename ) ;
}
2004-01-15 05:26:47 +08:00
void Monitor : : DumpImage ( Image * dump_image ) const
2003-03-26 19:57:29 +08:00
{
if ( image_count & & ! ( image_count % 10 ) )
{
2004-02-16 04:07:16 +08:00
static char filename [ PATH_MAX ] ;
2004-04-20 00:02:17 +08:00
static char new_filename [ PATH_MAX ] ;
snprintf ( filename , sizeof ( filename ) , " %s.jpg " , name ) ;
snprintf ( new_filename , sizeof ( new_filename ) , " %s-new.jpg " , name ) ;
2004-01-15 05:26:47 +08:00
dump_image - > WriteJpeg ( new_filename ) ;
2003-03-26 19:57:29 +08:00
rename ( new_filename , filename ) ;
}
}
bool Monitor : : Analyse ( )
{
2003-06-12 22:29:54 +08:00
if ( shared_data - > last_read_index = = shared_data - > last_write_index )
2003-03-26 19:57:29 +08:00
{
return ( false ) ;
}
struct timeval now ;
gettimeofday ( & now , & dummy_tz ) ;
if ( image_count & & ! ( image_count % fps_report_interval ) )
{
fps = double ( fps_report_interval ) / ( now . tv_sec - last_fps_time ) ;
Info ( ( " %s: %d - Processing at %.2f fps " , name , image_count , fps ) ) ;
last_fps_time = now . tv_sec ;
}
2003-04-22 22:25:31 +08:00
int index ;
2004-02-16 03:53:10 +08:00
if ( opt_adaptive_skip )
2003-04-17 23:39:44 +08:00
{
2003-06-12 22:29:54 +08:00
int read_margin = shared_data - > last_read_index - shared_data - > last_write_index ;
2003-04-22 22:16:50 +08:00
if ( read_margin < 0 ) read_margin + = image_buffer_count ;
2003-04-17 23:39:44 +08:00
2003-04-22 22:16:50 +08:00
int step = 1 ;
if ( read_margin > 0 )
{
step = ( 9 * image_buffer_count ) / ( 5 * read_margin ) ;
}
2003-04-21 04:52:14 +08:00
2003-06-12 22:29:54 +08:00
int pending_frames = shared_data - > last_write_index - shared_data - > last_read_index ;
2003-04-22 22:16:50 +08:00
if ( pending_frames < 0 ) pending_frames + = image_buffer_count ;
2004-05-06 00:22:37 +08:00
Debug ( 4 , ( " RI:%d, WI: %d, PF = %d, RM = %d, Step = %d " , shared_data - > last_read_index , shared_data - > last_write_index , pending_frames , read_margin , step ) ) ;
2003-04-22 22:16:50 +08:00
if ( step < = pending_frames )
{
2003-06-12 22:29:54 +08:00
index = ( shared_data - > last_read_index + step ) % image_buffer_count ;
2003-04-22 22:16:50 +08:00
}
else
{
if ( pending_frames )
{
Warning ( ( " Approaching buffer overrun, consider increasing ring buffer size " ) ) ;
}
2003-06-12 22:29:54 +08:00
index = shared_data - > last_write_index % image_buffer_count ;
2003-04-22 22:16:50 +08:00
}
2003-04-17 23:39:44 +08:00
}
else
{
2003-06-12 22:29:54 +08:00
index = shared_data - > last_write_index % image_buffer_count ;
2003-04-17 23:39:44 +08:00
}
2003-04-22 22:16:50 +08:00
2003-03-26 19:57:29 +08:00
Snapshot * snap = & image_buffer [ index ] ;
struct timeval * timestamp = snap - > timestamp ;
2004-01-15 05:26:47 +08:00
Image * snap_image = snap - > image ;
static struct timeval * * timestamps ;
2004-02-16 04:07:16 +08:00
static Image * * images ;
2004-03-10 01:04:15 +08:00
static int last_section_mod = 0 ;
2003-03-26 19:57:29 +08:00
unsigned int score = 0 ;
if ( Ready ( ) )
{
2003-09-23 17:52:45 +08:00
if ( function ! = RECORD & & shared_data - > force_state ! = FORCE_OFF )
2004-01-15 05:26:47 +08:00
score = Compare ( * snap_image ) ;
2003-06-12 22:29:54 +08:00
if ( shared_data - > force_state = = FORCE_ON )
2003-07-04 20:31:36 +08:00
score = ( int ) config . Item ( ZM_FORCED_ALARM_SCORE ) ;
2003-03-26 19:57:29 +08:00
2003-09-23 17:52:45 +08:00
if ( function = = RECORD | | function = = MOCORD )
2003-03-26 19:57:29 +08:00
{
2004-02-20 17:47:49 +08:00
if ( event )
{
if ( state = = IDLE | | state = = TAPE )
{
2004-03-10 01:04:15 +08:00
int section_mod = timestamp - > tv_sec % section_length ;
if ( section_mod < last_section_mod )
2004-02-20 17:47:49 +08:00
{
Info ( ( " Ended event " ) ) ;
gettimeofday ( & ( event - > EndTime ( ) ) , & dummy_tz ) ;
delete event ;
event = 0 ;
2004-03-10 01:04:15 +08:00
last_section_mod = 0 ;
}
else
{
last_section_mod = section_mod ;
2004-02-20 17:47:49 +08:00
}
}
}
2003-09-23 17:52:45 +08:00
if ( ! event )
2003-03-26 19:57:29 +08:00
{
2003-09-23 17:52:45 +08:00
// Create event
2003-03-26 19:57:29 +08:00
event = new Event ( this , * timestamp ) ;
2003-09-23 17:52:45 +08:00
Info ( ( " %s: %03d - Starting new event " , name , image_count ) ) ;
//if ( (bool)config.Item( ZM_OVERLAP_TIMED_EVENTS ) )
2004-02-16 03:53:10 +08:00
if ( true )
2003-09-23 17:52:45 +08:00
{
int pre_index = ( ( index + image_buffer_count ) - pre_event_count ) % image_buffer_count ;
2004-01-15 05:26:47 +08:00
if ( ! timestamps ) timestamps = new struct timeval * [ pre_event_count ] ;
2004-02-16 04:07:16 +08:00
if ( ! images ) images = new Image * [ pre_event_count ] ;
2003-09-23 17:52:45 +08:00
for ( int i = 0 ; i < pre_event_count ; i + + )
{
timestamps [ i ] = image_buffer [ pre_index ] . timestamp ;
images [ i ] = image_buffer [ pre_index ] . image ;
pre_index = ( pre_index + 1 ) % image_buffer_count ;
}
2004-02-16 04:07:16 +08:00
event - > AddFrames ( pre_event_count , images , timestamps ) ;
2003-09-23 17:52:45 +08:00
}
shared_data - > state = state = TAPE ;
}
}
if ( score )
{
2004-03-30 19:05:47 +08:00
if ( state = = IDLE | | state = = TAPE )
2003-09-23 17:52:45 +08:00
{
2003-03-26 19:57:29 +08:00
Info ( ( " %s: %03d - Gone into alarm state " , name , image_count ) ) ;
2003-09-23 17:52:45 +08:00
if ( function ! = MOCORD )
2003-03-26 19:57:29 +08:00
{
2003-09-23 17:52:45 +08:00
event = new Event ( this , * timestamp ) ;
2003-05-02 18:15:09 +08:00
2003-09-23 17:52:45 +08:00
int pre_index = ( ( index + image_buffer_count ) - pre_event_count ) % image_buffer_count ;
2004-01-15 05:26:47 +08:00
if ( ! timestamps ) timestamps = new struct timeval * [ pre_event_count ] ;
2004-02-16 04:07:16 +08:00
if ( ! images ) images = new Image * [ pre_event_count ] ;
2003-09-23 17:52:45 +08:00
for ( int i = 0 ; i < pre_event_count ; i + + )
{
timestamps [ i ] = image_buffer [ pre_index ] . timestamp ;
images [ i ] = image_buffer [ pre_index ] . image ;
pre_index = ( pre_index + 1 ) % image_buffer_count ;
}
2004-02-16 04:07:16 +08:00
event - > AddFrames ( pre_event_count , images , timestamps ) ;
2003-03-26 19:57:29 +08:00
}
}
2003-06-12 22:29:54 +08:00
shared_data - > state = state = ALARM ;
2003-03-26 19:57:29 +08:00
last_alarm_count = image_count ;
}
else
{
if ( state = = ALARM )
{
2003-06-12 22:29:54 +08:00
shared_data - > state = state = ALERT ;
2003-03-26 19:57:29 +08:00
}
else if ( state = = ALERT )
{
if ( image_count - last_alarm_count > post_event_count )
{
Info ( ( " %s: %03d - Left alarm state (%d) - %d(%d) images " , name , image_count , event - > Id ( ) , event - > Frames ( ) , event - > AlarmFrames ( ) ) ) ;
2003-06-12 22:29:54 +08:00
shared_data - > last_event = event - > Id ( ) ;
2003-09-23 17:52:45 +08:00
if ( function ! = MOCORD )
{
shared_data - > state = state = IDLE ;
delete event ;
event = 0 ;
}
else
{
shared_data - > state = state = TAPE ;
}
2003-03-26 19:57:29 +08:00
}
}
}
if ( state ! = IDLE )
{
if ( state = = ALARM )
{
2004-02-16 03:53:10 +08:00
if ( create_analysis_images )
2003-03-26 19:57:29 +08:00
{
2004-03-30 19:05:47 +08:00
bool got_anal_image = false ;
2004-01-15 05:26:47 +08:00
Image alarm_image ( * snap_image ) ;
2003-11-21 18:38:41 +08:00
for ( int i = 0 ; i < n_zones ; i + + )
2003-03-26 19:57:29 +08:00
{
2003-11-21 18:38:41 +08:00
if ( zones [ i ] - > Alarmed ( ) )
2003-03-26 19:57:29 +08:00
{
2004-03-30 19:05:47 +08:00
if ( zones [ i ] - > AlarmImage ( ) )
{
alarm_image . Overlay ( * ( zones [ i ] - > AlarmImage ( ) ) ) ;
got_anal_image = true ;
}
2003-11-21 18:38:41 +08:00
if ( record_event_stats )
{
zones [ i ] - > RecordStats ( event ) ;
}
2003-03-26 19:57:29 +08:00
}
}
2004-03-30 19:05:47 +08:00
if ( got_anal_image )
{
event - > AddFrame ( snap_image , * timestamp , score , & alarm_image ) ;
}
else
{
event - > AddFrame ( snap_image , * timestamp , score ) ;
}
2003-11-21 18:38:41 +08:00
}
else
{
2004-02-16 04:07:16 +08:00
event - > AddFrame ( snap_image , * timestamp , score ) ;
2003-03-26 19:57:29 +08:00
}
}
2003-10-08 22:49:26 +08:00
else if ( state = = ALERT )
2003-03-26 19:57:29 +08:00
{
2004-02-16 04:07:16 +08:00
event - > AddFrame ( snap_image , * timestamp ) ;
2003-03-26 19:57:29 +08:00
}
2003-10-08 22:49:26 +08:00
else if ( state = = TAPE )
{
if ( ! ( image_count % ( frame_skip + 1 ) ) )
{
2004-03-04 23:13:10 +08:00
if ( bulk_frame_interval > 1 )
{
event - > AddFrame ( snap_image , * timestamp , - 1 ) ;
}
else
{
event - > AddFrame ( snap_image , * timestamp ) ;
}
2003-10-08 22:49:26 +08:00
}
}
2003-03-26 19:57:29 +08:00
}
2003-09-23 17:52:45 +08:00
if ( function = = RECORD | | function = = MOCORD )
{
if ( state = = IDLE | | state = = TAPE )
{
2004-03-10 01:04:15 +08:00
int section_mod = timestamp - > tv_sec % section_length ;
if ( section_mod < last_section_mod )
2003-09-23 17:52:45 +08:00
{
Info ( ( " Ended event " ) ) ;
2003-10-08 20:54:35 +08:00
gettimeofday ( & ( event - > EndTime ( ) ) , & dummy_tz ) ;
2003-09-23 17:52:45 +08:00
delete event ;
event = 0 ;
2004-03-10 01:04:15 +08:00
last_section_mod = 0 ;
}
else
{
last_section_mod = section_mod ;
2003-09-23 17:52:45 +08:00
}
}
}
2003-03-26 19:57:29 +08:00
}
2003-03-27 17:31:13 +08:00
2004-02-16 03:53:10 +08:00
if ( ( function = = MODECT | | function = = MOCORD ) & & ( blend_alarmed_images | | state ! = ALARM ) )
2003-03-27 17:31:13 +08:00
{
2004-01-15 05:26:47 +08:00
ref_image . Blend ( * snap_image , ref_blend_perc ) ;
2003-03-27 17:31:13 +08:00
}
2003-03-26 19:57:29 +08:00
2003-06-12 22:29:54 +08:00
shared_data - > last_read_index = index % image_buffer_count ;
2003-03-26 19:57:29 +08:00
image_count + + ;
return ( true ) ;
}
void Monitor : : ReloadZones ( )
{
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Reloading zones for monitor %s " , name ) ) ;
2003-03-26 19:57:29 +08:00
for ( int i = 0 ; i < n_zones ; i + + )
{
delete zones [ i ] ;
}
//delete[] zones;
n_zones = Zone : : Load ( this , zones ) ;
DumpZoneImage ( ) ;
}
2003-09-23 17:52:45 +08:00
int Monitor : : Load ( int device , Monitor * * & monitors , Purpose purpose )
2003-03-26 19:57:29 +08:00
{
2003-07-04 04:39:47 +08:00
static char sql [ BUFSIZ ] ;
2003-03-26 19:57:29 +08:00
if ( device = = - 1 )
{
2004-04-20 00:02:17 +08:00
strncpy ( sql , " select Id, Name, Function+0, Device, Channel, Format, Width, Height, Palette, Orientation+0, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, SectionLength, FrameSkip, MaxFPS, FPSReportInterval, RefBlendPerc from Monitors where Function != 'None' and Type = 'Local' " , sizeof ( sql ) ) ;
2003-03-26 19:57:29 +08:00
}
else
{
2004-04-20 00:02:17 +08:00
snprintf ( sql , sizeof ( sql ) , " select Id, Name, Function+0, Device, Channel, Format, Width, Height, Palette, Orientation+0, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, SectionLength, FrameSkip, MaxFPS, FPSReportInterval, RefBlendPerc from Monitors where Function != 'None' and Type = 'Local' and Device = %d " , device ) ;
2003-03-26 19:57:29 +08:00
}
if ( mysql_query ( & dbconn , sql ) )
{
Error ( ( " Can't run query: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
MYSQL_RES * result = mysql_store_result ( & dbconn ) ;
if ( ! result )
{
Error ( ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
int n_monitors = mysql_num_rows ( result ) ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Got %d monitors " , n_monitors ) ) ;
2003-03-26 19:57:29 +08:00
delete [ ] monitors ;
monitors = new Monitor * [ n_monitors ] ;
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + )
{
2003-10-08 22:49:26 +08:00
monitors [ i ] = new Monitor (
atoi ( dbrow [ 0 ] ) , // Id
dbrow [ 1 ] , // Name
atoi ( dbrow [ 2 ] ) , // Function
atoi ( dbrow [ 3 ] ) , // Device
atoi ( dbrow [ 4 ] ) , // Channel
atoi ( dbrow [ 5 ] ) , // Format
atoi ( dbrow [ 6 ] ) , // Width
atoi ( dbrow [ 7 ] ) , // Height
atoi ( dbrow [ 8 ] ) , // Palette
atoi ( dbrow [ 9 ] ) , // Orientation
dbrow [ 10 ] , // LabelFormat
Coord ( atoi ( dbrow [ 11 ] ) , atoi ( dbrow [ 12 ] ) ) , // LabelX, LabelY
atoi ( dbrow [ 13 ] ) , // ImageBufferCount
atoi ( dbrow [ 14 ] ) , // WarmupCount
atoi ( dbrow [ 15 ] ) , // PreEventCount
atoi ( dbrow [ 16 ] ) , // PostEventCount
atoi ( dbrow [ 17 ] ) , // SectionLength
atoi ( dbrow [ 18 ] ) , // FrameSkip
atof ( dbrow [ 19 ] ) > 0.0 ? int ( DT_PREC_3 / atof ( dbrow [ 19 ] ) ) : 0 , // MaxFPS
atoi ( dbrow [ 20 ] ) , // FPSReportInterval
atoi ( dbrow [ 21 ] ) , // RefBlendPerc
purpose
) ;
2003-03-26 19:57:29 +08:00
Zone * * zones = 0 ;
int n_zones = Zone : : Load ( monitors [ i ] , zones ) ;
monitors [ i ] - > AddZones ( n_zones , zones ) ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Loaded monitor %d(%s), %d zones " , atoi ( dbrow [ 0 ] ) , dbrow [ 1 ] , n_zones ) ) ;
2003-03-26 19:57:29 +08:00
}
if ( mysql_errno ( & dbconn ) )
{
Error ( ( " Can't fetch row: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
// Yadda yadda
mysql_free_result ( result ) ;
return ( n_monitors ) ;
}
2003-09-23 17:52:45 +08:00
int Monitor : : Load ( const char * host , const char * port , const char * path , Monitor * * & monitors , Purpose purpose )
2003-03-26 19:57:29 +08:00
{
2003-07-04 04:39:47 +08:00
static char sql [ BUFSIZ ] ;
2003-03-26 19:57:29 +08:00
if ( ! host )
{
2004-04-20 00:02:17 +08:00
strncpy ( sql , " select Id, Name, Function+0, Host, Port, Path, Width, Height, Palette, Orientation+0, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, SectionLength, FrameSkip, MaxFPS, FPSReportInterval, RefBlendPerc from Monitors where Function != 'None' and Type = 'Remote' " , sizeof ( sql ) ) ;
2003-03-26 19:57:29 +08:00
}
else
{
2004-04-20 00:02:17 +08:00
snprintf ( sql , sizeof ( sql ) , " select Id, Name, Function+0, Host, Port, Path, Width, Height, Palette, Orientation+0, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, SectionLength, FrameSkip, MaxFPS, FPSReportInterval, RefBlendPerc from Monitors where Function != 'None' and Type = 'Remote' and Host = '%s' and Port = '%s' and Path = '%s' " , host , port , path ) ;
2003-03-26 19:57:29 +08:00
}
if ( mysql_query ( & dbconn , sql ) )
{
Error ( ( " Can't run query: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
MYSQL_RES * result = mysql_store_result ( & dbconn ) ;
if ( ! result )
{
Error ( ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
int n_monitors = mysql_num_rows ( result ) ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Got %d monitors " , n_monitors ) ) ;
2003-03-26 19:57:29 +08:00
delete [ ] monitors ;
monitors = new Monitor * [ n_monitors ] ;
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + )
{
2003-10-08 22:49:26 +08:00
monitors [ i ] = new Monitor (
atoi ( dbrow [ 0 ] ) , // Id
dbrow [ 1 ] , // Name
atoi ( dbrow [ 2 ] ) , // Function
dbrow [ 3 ] , // Host
dbrow [ 4 ] , // Port
dbrow [ 5 ] , // Path
atoi ( dbrow [ 6 ] ) , // Width
atoi ( dbrow [ 7 ] ) , // Height
atoi ( dbrow [ 8 ] ) , // Palette
atoi ( dbrow [ 9 ] ) , // Orientation
dbrow [ 10 ] , // LabelFormat
Coord ( atoi ( dbrow [ 11 ] ) , atoi ( dbrow [ 12 ] ) ) , // LabelX, LabelY
atoi ( dbrow [ 13 ] ) , // ImageBufferCount
atoi ( dbrow [ 14 ] ) , // WarmupCount
atoi ( dbrow [ 15 ] ) , // PreEventCount
atoi ( dbrow [ 16 ] ) , // PostEventCount
atoi ( dbrow [ 17 ] ) , // SectionLength
atoi ( dbrow [ 18 ] ) , // FrameSkip
atof ( dbrow [ 19 ] ) > 0.0 ? int ( DT_PREC_3 / atof ( dbrow [ 19 ] ) ) : 0 , // MaxFPS
atoi ( dbrow [ 20 ] ) , // FPSReportInterval
atoi ( dbrow [ 21 ] ) , // RefBlendPerc
purpose
) ;
2003-03-26 19:57:29 +08:00
Zone * * zones = 0 ;
int n_zones = Zone : : Load ( monitors [ i ] , zones ) ;
monitors [ i ] - > AddZones ( n_zones , zones ) ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Loaded monitor %d(%s), %d zones " , atoi ( dbrow [ 0 ] ) , dbrow [ 1 ] , n_zones ) ) ;
2003-03-26 19:57:29 +08:00
}
if ( mysql_errno ( & dbconn ) )
{
Error ( ( " Can't fetch row: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
// Yadda yadda
mysql_free_result ( result ) ;
return ( n_monitors ) ;
}
2003-09-23 17:52:45 +08:00
Monitor * Monitor : : Load ( int id , bool load_zones , Purpose purpose )
2003-03-26 19:57:29 +08:00
{
2003-07-04 04:39:47 +08:00
static char sql [ BUFSIZ ] ;
2004-04-20 00:02:17 +08:00
snprintf ( sql , sizeof ( sql ) , " select Id, Name, Type, Function+0, Device, Channel, Format, Host, Port, Path, Width, Height, Palette, Orientation+0, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, SectionLength, FrameSkip, MaxFPS, FPSReportInterval, RefBlendPerc from Monitors where Id = %d " , id ) ;
2003-03-26 19:57:29 +08:00
if ( mysql_query ( & dbconn , sql ) )
{
Error ( ( " Can't run query: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
MYSQL_RES * result = mysql_store_result ( & dbconn ) ;
if ( ! result )
{
Error ( ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
int n_monitors = mysql_num_rows ( result ) ;
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Got %d monitors " , n_monitors ) ) ;
2003-03-26 19:57:29 +08:00
Monitor * monitor = 0 ;
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + )
{
if ( ! strcmp ( dbrow [ 2 ] , " Local " ) )
{
2003-10-08 22:49:26 +08:00
monitor = new Monitor (
atoi ( dbrow [ 0 ] ) , // Id
dbrow [ 1 ] , // Name
atoi ( dbrow [ 3 ] ) , // Function
atoi ( dbrow [ 4 ] ) , // Device
atoi ( dbrow [ 5 ] ) , // Channel
atoi ( dbrow [ 6 ] ) , // Format
atoi ( dbrow [ 10 ] ) , // Width
atoi ( dbrow [ 11 ] ) , // Height
atoi ( dbrow [ 12 ] ) , // Palette
atoi ( dbrow [ 13 ] ) , // Orientation
dbrow [ 14 ] , // LabelFormat
Coord ( atoi ( dbrow [ 15 ] ) , atoi ( dbrow [ 16 ] ) ) , // LabelX, LabelY
atoi ( dbrow [ 17 ] ) , // ImageBufferCount
atoi ( dbrow [ 18 ] ) , // WarmupCount
atoi ( dbrow [ 19 ] ) , // PreEventCount
atoi ( dbrow [ 20 ] ) , // PostEventCount
atoi ( dbrow [ 21 ] ) , // SectionLength
atoi ( dbrow [ 22 ] ) , // FrameSkip
atof ( dbrow [ 23 ] ) > 0.0 ? int ( DT_PREC_3 / atof ( dbrow [ 23 ] ) ) : 0 , // MaxFPS
atoi ( dbrow [ 24 ] ) , // FPSReportInterval
atoi ( dbrow [ 25 ] ) , // RefBlendPerc
purpose
) ;
2003-03-26 19:57:29 +08:00
}
else
{
2003-10-08 22:49:26 +08:00
monitor = new Monitor (
atoi ( dbrow [ 0 ] ) , // Id
dbrow [ 1 ] , // Name
atoi ( dbrow [ 3 ] ) , // Function
dbrow [ 7 ] , // Host
dbrow [ 8 ] , // Port
dbrow [ 9 ] , // Path
atoi ( dbrow [ 10 ] ) , // Width
atoi ( dbrow [ 11 ] ) , // Height
atoi ( dbrow [ 12 ] ) , // Palette
atoi ( dbrow [ 13 ] ) , // Orientation
dbrow [ 14 ] , // LabelFormat
Coord ( atoi ( dbrow [ 15 ] ) , atoi ( dbrow [ 16 ] ) ) , // LabelX, LabelY
atoi ( dbrow [ 17 ] ) , // ImageBufferCount
atoi ( dbrow [ 18 ] ) , // WarmupCount
atoi ( dbrow [ 19 ] ) , // PreEventCount
atoi ( dbrow [ 20 ] ) , // PostEventCount
atoi ( dbrow [ 21 ] ) , // SectionLength
atoi ( dbrow [ 22 ] ) , // FrameSkip
atof ( dbrow [ 23 ] ) > 0.0 ? int ( DT_PREC_3 / atof ( dbrow [ 23 ] ) ) : 0 , // MaxFPS
atoi ( dbrow [ 24 ] ) , // FPSReportInterval
atoi ( dbrow [ 25 ] ) , // RefBlendPerc
purpose
) ;
2003-03-26 19:57:29 +08:00
}
int n_zones = 0 ;
if ( load_zones )
{
Zone * * zones = 0 ;
n_zones = Zone : : Load ( monitor , zones ) ;
monitor - > AddZones ( n_zones , zones ) ;
}
2004-03-17 18:28:07 +08:00
Debug ( 1 , ( " Loaded monitor %d(%s), %d zones " , atoi ( dbrow [ 0 ] ) , dbrow [ 1 ] , n_zones ) ) ;
2003-03-26 19:57:29 +08:00
}
if ( mysql_errno ( & dbconn ) )
{
Error ( ( " Can't fetch row: %s " , mysql_error ( & dbconn ) ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
// Yadda yadda
mysql_free_result ( result ) ;
return ( monitor ) ;
}
2004-03-15 17:37:21 +08:00
void Monitor : : StreamImages ( int scale , int maxfps , time_t ttl )
2003-03-26 19:57:29 +08:00
{
2004-03-04 23:05:54 +08:00
fprintf ( stdout , " Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame \r \n \r \n " ) ;
2004-03-13 22:07:23 +08:00
fprintf ( stdout , " --ZoneMinderFrame \r \n " ) ;
2003-10-19 21:54:40 +08:00
2004-03-15 17:37:21 +08:00
int fps = int ( GetFPS ( ) ) ;
if ( ! fps )
fps = 5 ;
int min_fps = 1 ;
int max_fps = maxfps ;
int base_fps = int ( GetFPS ( ) ) ;
int effective_fps = base_fps ;
int frame_mod = 1 ;
// Min frame repeat?
while ( effective_fps > max_fps )
{
effective_fps / = 2 ;
frame_mod * = 2 ;
}
Debug ( 1 , ( " BFPS:%d, EFPS:%d, FM:%d " , base_fps , effective_fps , frame_mod ) ) ;
2003-03-26 19:57:29 +08:00
int last_read_index = image_buffer_count ;
2003-10-19 18:11:07 +08:00
2004-01-15 05:26:47 +08:00
time_t stream_start_time ;
time ( & stream_start_time ) ;
2003-10-19 18:11:07 +08:00
2004-03-15 17:37:21 +08:00
int frame_count = 0 ;
struct timeval base_time ;
struct DeltaTimeval delta_time ;
int img_buffer_size = 0 ;
static JOCTET img_buffer [ ZM_MAX_IMAGE_SIZE ] ;
Image scaled_image ;
2003-03-26 19:57:29 +08:00
while ( true )
{
2004-03-04 23:05:54 +08:00
if ( feof ( stdout ) | | ferror ( stdout ) )
2003-04-04 18:00:57 +08:00
{
break ;
}
2003-06-12 22:29:54 +08:00
if ( last_read_index ! = shared_data - > last_write_index )
2003-03-26 19:57:29 +08:00
{
2004-03-15 17:37:21 +08:00
if ( ( frame_mod = = 1 ) | | ( ( frame_count % frame_mod ) = = 0 ) )
2003-10-19 18:11:07 +08:00
{
2004-03-15 17:37:21 +08:00
// Send the next frame
last_read_index = shared_data - > last_write_index ;
int index = shared_data - > last_write_index % image_buffer_count ;
//Info(( "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer ));
Snapshot * snap = & image_buffer [ index ] ;
Image * snap_image = snap - > image ;
if ( scale ! = 100 )
{
scaled_image . Assign ( * snap_image ) ;
scaled_image . Scale ( scale ) ;
snap_image = & scaled_image ;
}
2004-02-16 04:07:16 +08:00
if ( ! timestamp_on_capture )
{
TimestampImage ( snap_image , snap - > timestamp - > tv_sec ) ;
}
2004-02-16 07:35:15 +08:00
snap_image - > EncodeJpeg ( img_buffer , & img_buffer_size ) ;
2003-10-19 18:11:07 +08:00
2004-03-15 17:37:21 +08:00
fprintf ( stdout , " Content-Length: %d \r \n " , img_buffer_size ) ;
fprintf ( stdout , " Content-Type: image/jpeg \r \n \r \n " ) ;
fwrite ( img_buffer , img_buffer_size , 1 , stdout ) ;
fprintf ( stdout , " \r \n \r \n --ZoneMinderFrame \r \n " ) ;
2003-10-19 18:11:07 +08:00
2004-03-15 17:37:21 +08:00
if ( ttl )
2004-02-16 04:07:16 +08:00
{
2004-03-15 17:37:21 +08:00
time_t now ;
time ( & now ) ;
if ( ( now - stream_start_time ) > ttl )
{
break ;
}
2004-02-16 04:07:16 +08:00
}
2003-03-26 19:57:29 +08:00
}
2004-03-15 17:37:21 +08:00
frame_count + + ;
2003-03-26 19:57:29 +08:00
}
2004-03-15 17:37:21 +08:00
usleep ( ZM_SAMPLE_RATE ) ;
2003-03-26 19:57:29 +08:00
}
}
2004-04-19 21:03:16 +08:00
void Monitor : : SingleImage ( int scale )
{
int last_read_index = shared_data - > last_write_index ;
int img_buffer_size = 0 ;
static JOCTET img_buffer [ ZM_MAX_IMAGE_SIZE ] ;
Image scaled_image ;
int index = shared_data - > last_write_index % image_buffer_count ;
Snapshot * snap = & image_buffer [ index ] ;
Image * snap_image = snap - > image ;
if ( scale ! = 100 )
{
scaled_image . Assign ( * snap_image ) ;
scaled_image . Scale ( scale ) ;
snap_image = & scaled_image ;
}
if ( ! timestamp_on_capture )
{
TimestampImage ( snap_image , snap - > timestamp - > tv_sec ) ;
}
snap_image - > EncodeJpeg ( img_buffer , & img_buffer_size ) ;
fprintf ( stdout , " Content-Length: %d \r \n " , img_buffer_size ) ;
fprintf ( stdout , " Content-Type: image/jpeg \r \n \r \n " ) ;
fwrite ( img_buffer , img_buffer_size , 1 , stdout ) ;
}
2004-03-04 23:05:54 +08:00
# if HAVE_LIBAVCODEC
2004-03-15 17:37:21 +08:00
void Monitor : : StreamMpeg ( const char * format , int scale , int maxfps , int bitrate )
2004-03-04 23:05:54 +08:00
{
2004-03-15 07:27:36 +08:00
bool timed_frames = ( bool ) config . Item ( ZM_VIDEO_TIMED_FRAMES ) ;
2004-03-11 19:18:14 +08:00
2004-03-04 23:05:54 +08:00
int fps = int ( GetFPS ( ) ) ;
if ( ! fps )
fps = 5 ;
2004-03-11 19:18:14 +08:00
int min_fps = 1 ;
int max_fps = maxfps ;
int base_fps = int ( GetFPS ( ) ) ;
int effective_fps = base_fps ;
2004-03-04 23:05:54 +08:00
2004-03-11 19:18:14 +08:00
int frame_mod = 1 ;
// Min frame repeat?
while ( effective_fps > max_fps )
2004-03-04 23:05:54 +08:00
{
2004-03-11 19:18:14 +08:00
effective_fps / = 2 ;
frame_mod * = 2 ;
}
2004-03-04 23:05:54 +08:00
2004-03-15 17:37:21 +08:00
Debug ( 1 , ( " BFPS:%d, EFPS:%d, FM:%d " , base_fps , effective_fps , frame_mod ) ) ;
2004-03-04 23:05:54 +08:00
2004-03-11 19:18:14 +08:00
VideoStream vid_stream ( " pipe: " , format , bitrate , fps , camera - > Colours ( ) , ( width * scale ) / ZM_SCALE_SCALE , ( height * scale ) / ZM_SCALE_SCALE ) ;
2004-03-04 23:05:54 +08:00
2004-03-11 19:18:14 +08:00
int last_read_index = image_buffer_count ;
2004-03-04 23:05:54 +08:00
2004-03-11 19:18:14 +08:00
time_t stream_start_time ;
time ( & stream_start_time ) ;
2004-03-04 23:05:54 +08:00
2004-03-08 18:33:19 +08:00
int frame_count = 0 ;
struct timeval base_time ;
struct DeltaTimeval delta_time ;
2004-03-11 19:18:14 +08:00
Image scaled_image ;
2004-03-04 23:05:54 +08:00
while ( true )
{
if ( feof ( stdout ) | | ferror ( stdout ) )
{
break ;
}
if ( last_read_index ! = shared_data - > last_write_index )
{
2004-03-11 19:18:14 +08:00
if ( ( frame_mod = = 1 ) | | ( ( frame_count % frame_mod ) = = 0 ) )
2004-03-04 23:05:54 +08:00
{
2004-03-11 19:18:14 +08:00
// Send the next frame
last_read_index = shared_data - > last_write_index ;
int index = shared_data - > last_write_index % image_buffer_count ;
//Info(( "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer ));
Snapshot * snap = & image_buffer [ index ] ;
Image * snap_image = snap - > image ;
2004-03-15 17:37:21 +08:00
if ( scale ! = 100 )
2004-03-11 19:18:14 +08:00
{
scaled_image . Assign ( * snap_image ) ;
2004-03-04 23:05:54 +08:00
2004-03-11 19:18:14 +08:00
scaled_image . Scale ( scale ) ;
2004-03-04 23:05:54 +08:00
2004-03-11 19:18:14 +08:00
snap_image = & scaled_image ;
2004-03-04 23:05:54 +08:00
}
2004-03-15 17:37:21 +08:00
if ( ! timestamp_on_capture )
{
TimestampImage ( snap_image , snap - > timestamp - > tv_sec ) ;
}
2004-03-04 23:05:54 +08:00
2004-03-11 19:18:14 +08:00
if ( ! frame_count )
{
base_time = * ( snap - > timestamp ) ;
}
DELTA_TIMEVAL ( delta_time , * ( snap - > timestamp ) , base_time , DT_PREC_3 ) ;
double pts = vid_stream . EncodeFrame ( snap_image - > Buffer ( ) , snap_image - > Size ( ) , timed_frames , delta_time . delta ) ;
//Info(( "DTD:%d, PTS:%lf", delta_time.delta, pts ));
2004-03-08 18:33:19 +08:00
}
2004-03-11 19:18:14 +08:00
frame_count + + ;
2004-03-04 23:05:54 +08:00
}
2004-03-11 19:18:14 +08:00
usleep ( ZM_SAMPLE_RATE ) ;
2004-03-04 23:05:54 +08:00
}
}
# endif // HAVE_LIBAVCODEC
2003-03-26 19:57:29 +08:00
bool Monitor : : DumpSettings ( char * output , bool verbose )
{
output [ 0 ] = 0 ;
sprintf ( output + strlen ( output ) , " Id : %d \n " , id ) ;
sprintf ( output + strlen ( output ) , " Name : %s \n " , name ) ;
sprintf ( output + strlen ( output ) , " Type : %s \n " , camera - > IsLocal ( ) ? " Local " : " Remote " ) ;
if ( camera - > IsLocal ( ) )
{
sprintf ( output + strlen ( output ) , " Device : %d \n " , ( ( LocalCamera * ) camera ) - > Device ( ) ) ;
sprintf ( output + strlen ( output ) , " Channel : %d \n " , ( ( LocalCamera * ) camera ) - > Channel ( ) ) ;
sprintf ( output + strlen ( output ) , " Format : %d \n " , ( ( LocalCamera * ) camera ) - > Format ( ) ) ;
}
else
{
sprintf ( output + strlen ( output ) , " Host : %s \n " , ( ( RemoteCamera * ) camera ) - > Host ( ) ) ;
sprintf ( output + strlen ( output ) , " Port : %s \n " , ( ( RemoteCamera * ) camera ) - > Port ( ) ) ;
sprintf ( output + strlen ( output ) , " Path : %s \n " , ( ( RemoteCamera * ) camera ) - > Path ( ) ) ;
}
2003-05-02 23:03:16 +08:00
sprintf ( output + strlen ( output ) , " Width : %d \n " , camera - > Width ( ) ) ;
2003-03-26 19:57:29 +08:00
sprintf ( output + strlen ( output ) , " Height : %d \n " , camera - > Height ( ) ) ;
2003-04-13 00:17:17 +08:00
sprintf ( output + strlen ( output ) , " Palette : %d \n " , camera - > Palette ( ) ) ;
sprintf ( output + strlen ( output ) , " Colours : %d \n " , camera - > Colours ( ) ) ;
2003-03-26 19:57:29 +08:00
sprintf ( output + strlen ( output ) , " Label Format : %s \n " , label_format ) ;
sprintf ( output + strlen ( output ) , " Label Coord : %d,%d \n " , label_coord . X ( ) , label_coord . Y ( ) ) ;
2003-03-27 06:12:25 +08:00
sprintf ( output + strlen ( output ) , " Image Buffer Count : %d \n " , image_buffer_count ) ;
2003-03-26 19:57:29 +08:00
sprintf ( output + strlen ( output ) , " Warmup Count : %d \n " , warmup_count ) ;
sprintf ( output + strlen ( output ) , " Pre Event Count : %d \n " , pre_event_count ) ;
sprintf ( output + strlen ( output ) , " Post Event Count : %d \n " , post_event_count ) ;
2003-09-23 17:52:45 +08:00
sprintf ( output + strlen ( output ) , " Section Length : %d \n " , section_length ) ;
2003-05-16 18:17:05 +08:00
sprintf ( output + strlen ( output ) , " Maximum FPS : %.2f \n " , capture_delay ? DT_PREC_3 / capture_delay : 0.0 ) ;
2003-03-26 19:57:29 +08:00
sprintf ( output + strlen ( output ) , " Reference Blend %%ge : %d \n " , ref_blend_perc ) ;
sprintf ( output + strlen ( output ) , " Function: %d - %s \n " , function ,
2003-09-23 17:52:45 +08:00
function = = OFF ? " None " : (
function = = MONITOR ? " Monitor " : (
function = = MODECT ? " Motion Detection " : (
function = = RECORD ? " Continuous Record " : (
function = = MOCORD ? " Continuous Record with Motion Detection " : " Unknown "
) ) ) ) ) ;
2003-03-26 19:57:29 +08:00
sprintf ( output + strlen ( output ) , " Zones : %d \n " , n_zones ) ;
for ( int i = 0 ; i < n_zones ; i + + )
{
zones [ i ] - > DumpSettings ( output + strlen ( output ) , verbose ) ;
2004-02-18 23:35:51 +08:00
}
2003-03-26 19:57:29 +08:00
return ( true ) ;
}
2004-01-15 05:26:47 +08:00
unsigned int Monitor : : Compare ( const Image & comp_image )
2003-03-26 19:57:29 +08:00
{
bool alarm = false ;
unsigned int score = 0 ;
if ( n_zones < = 0 ) return ( alarm ) ;
2004-02-16 03:53:10 +08:00
if ( record_diag_images )
2004-01-28 01:03:45 +08:00
{
static char diag_path [ PATH_MAX ] = " " ;
if ( ! diag_path [ 0 ] )
{
2004-04-20 00:02:17 +08:00
snprintf ( diag_path , sizeof ( diag_path ) , " %s/%s/diag-r.jpg " , ( const char * ) config . Item ( ZM_DIR_EVENTS ) , name ) ;
2004-01-28 01:03:45 +08:00
}
ref_image . WriteJpeg ( diag_path ) ;
}
2004-01-15 05:26:47 +08:00
Image * delta_image = ref_image . Delta ( comp_image ) ;
2003-03-26 19:57:29 +08:00
2004-02-16 03:53:10 +08:00
if ( record_diag_images )
2004-01-28 01:03:45 +08:00
{
static char diag_path [ PATH_MAX ] = " " ;
if ( ! diag_path [ 0 ] )
{
2004-04-20 00:02:17 +08:00
snprintf ( diag_path , sizeof ( diag_path ) , " %s/%s/diag-d.jpg " , ( const char * ) config . Item ( ZM_DIR_EVENTS ) , name ) ;
2004-01-28 01:03:45 +08:00
}
delta_image - > WriteJpeg ( diag_path ) ;
}
2003-03-26 19:57:29 +08:00
// Blank out all exclusion zones
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
zone - > ClearAlarm ( ) ;
Debug ( 3 , ( " Blanking inactive zone %s " , zone - > Label ( ) ) ) ;
if ( ! zone - > IsInactive ( ) )
{
continue ;
}
delta_image - > Fill ( RGB_BLACK , & ( zone - > Limits ( ) ) ) ;
}
2003-04-15 19:54:08 +08:00
// Check preclusive zones first
2003-03-26 19:57:29 +08:00
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
2003-04-15 19:54:08 +08:00
if ( ! zone - > IsPreclusive ( ) )
2003-03-26 19:57:29 +08:00
{
continue ;
}
2003-04-15 19:54:08 +08:00
Debug ( 3 , ( " Checking preclusive zone %s " , zone - > Label ( ) ) ) ;
2003-03-26 19:57:29 +08:00
if ( zone - > CheckAlarms ( delta_image ) )
{
alarm = true ;
score + = zone - > Score ( ) ;
Debug ( 3 , ( " Zone is alarmed, zone score = %d " , zone - > Score ( ) ) ) ;
2003-04-13 20:20:00 +08:00
zone - > ResetStats ( ) ;
2003-03-26 19:57:29 +08:00
}
}
if ( alarm )
{
2003-04-13 20:20:00 +08:00
alarm = false ;
score = 0 ;
}
else
{
// Find all alarm pixels in active zones
2003-03-26 19:57:29 +08:00
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
2003-04-13 20:20:00 +08:00
if ( ! zone - > IsActive ( ) )
2003-03-26 19:57:29 +08:00
{
continue ;
}
2003-04-13 20:20:00 +08:00
Debug ( 3 , ( " Checking active zone %s " , zone - > Label ( ) ) ) ;
2003-03-26 19:57:29 +08:00
if ( zone - > CheckAlarms ( delta_image ) )
{
alarm = true ;
score + = zone - > Score ( ) ;
zone - > SetAlarm ( ) ;
Debug ( 3 , ( " Zone is alarmed, zone score = %d " , zone - > Score ( ) ) ) ;
}
}
2003-04-13 20:20:00 +08:00
if ( alarm )
2003-03-26 19:57:29 +08:00
{
2003-04-13 20:20:00 +08:00
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
2003-03-26 19:57:29 +08:00
{
2003-04-13 20:20:00 +08:00
Zone * zone = zones [ n_zone ] ;
if ( ! zone - > IsInclusive ( ) )
{
continue ;
}
Debug ( 3 , ( " Checking inclusive zone %s " , zone - > Label ( ) ) ) ;
if ( zone - > CheckAlarms ( delta_image ) )
{
alarm = true ;
score + = zone - > Score ( ) ;
zone - > SetAlarm ( ) ;
Debug ( 3 , ( " Zone is alarmed, zone score = %d " , zone - > Score ( ) ) ) ;
}
2003-03-26 19:57:29 +08:00
}
2003-04-13 20:20:00 +08:00
}
else
{
2003-11-21 18:38:41 +08:00
// Find all alarm pixels in exclusive zones
2003-04-13 20:20:00 +08:00
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
2003-03-26 19:57:29 +08:00
{
2003-04-13 20:20:00 +08:00
Zone * zone = zones [ n_zone ] ;
if ( ! zone - > IsExclusive ( ) )
{
continue ;
}
Debug ( 3 , ( " Checking exclusive zone %s " , zone - > Label ( ) ) ) ;
if ( zone - > CheckAlarms ( delta_image ) )
{
alarm = true ;
score + = zone - > Score ( ) ;
zone - > SetAlarm ( ) ;
Debug ( 3 , ( " Zone is alarmed, zone score = %d " , zone - > Score ( ) ) ) ;
}
2003-03-26 19:57:29 +08:00
}
}
}
delete delta_image ;
// This is a small and innocent hack to prevent scores of 0 being returned in alarm state
return ( score ? score : alarm ) ;
}