2003-03-26 19:57:29 +08:00
//
// ZoneMinder Monitor Class Implementation, $Date$, $Revision$
2008-07-25 17:33:23 +08:00
// Copyright (C) 2001-2008 Philip Coombes
2003-03-26 19:57:29 +08:00
//
// 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.
//
2008-07-14 23:21:16 +08:00
# include <sys/types.h>
# include <sys/stat.h>
2008-12-06 07:14:20 +08:00
# include <arpa/inet.h>
2007-08-30 02:11:09 +08:00
# include <glob.h>
2003-03-26 19:57:29 +08:00
# include "zm.h"
# include "zm_db.h"
2008-07-16 16:35:59 +08:00
# include "zm_time.h"
2004-03-04 23:05:54 +08:00
# include "zm_mpeg.h"
2007-08-30 02:11:09 +08:00
# include "zm_signal.h"
2003-03-26 19:57:29 +08:00
# include "zm_monitor.h"
2013-12-20 00:38:07 +08:00
# include "zm_video.h"
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L
2003-03-26 19:57:29 +08:00
# include "zm_local_camera.h"
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L
2003-03-26 19:57:29 +08:00
# include "zm_remote_camera.h"
2008-07-16 16:35:59 +08:00
# include "zm_remote_camera_http.h"
2008-10-17 00:11:49 +08:00
# if HAVE_LIBAVFORMAT
2008-07-16 16:35:59 +08:00
# include "zm_remote_camera_rtsp.h"
2008-10-17 00:11:49 +08:00
# endif // HAVE_LIBAVFORMAT
2005-10-18 05:55:02 +08:00
# include "zm_file_camera.h"
2009-01-20 23:01:32 +08:00
# if HAVE_LIBAVFORMAT
# include "zm_ffmpeg_camera.h"
# endif // HAVE_LIBAVFORMAT
2013-12-13 01:45:29 +08:00
# if HAVE_LIBVLC
# include "zm_libvlc_camera.h"
# endif // HAVE_LIBVLC
2013-11-04 23:10:07 +08:00
# if HAVE_LIBCURL
# include "zm_curl_camera.h"
# endif // HAVE_LIBCURL
2003-03-26 19:57:29 +08:00
2008-07-14 23:21:16 +08:00
# if ZM_MEM_MAPPED
# include <sys/mman.h>
# include <fcntl.h>
# else // ZM_MEM_MAPPED
# include <sys/ipc.h>
# include <sys/shm.h>
# endif // ZM_MEM_MAPPED
2015-05-18 08:18:54 +08:00
// SOLARIS - we don't have MAP_LOCKED on openSolaris/illumos
# ifndef MAP_LOCKED
# define MAP_LOCKED 0
# endif
2013-03-17 07:45:21 +08:00
//=============================================================================
std : : vector < std : : string > split ( const std : : string & s , char delim ) {
2016-04-04 22:11:48 +08:00
std : : vector < std : : string > elems ;
std : : stringstream ss ( s ) ;
std : : string item ;
while ( std : : getline ( ss , item , delim ) ) {
elems . push_back ( trimSpaces ( item ) ) ;
}
return elems ;
2013-03-17 07:45:21 +08:00
}
//=============================================================================
2006-01-23 02:31:55 +08:00
Monitor : : MonitorLink : : MonitorLink ( int p_id , const char * p_name ) : id ( p_id )
{
2016-04-04 22:11:48 +08:00
strncpy ( name , p_name , sizeof ( name ) ) ;
2006-01-23 02:31:55 +08:00
2008-07-14 23:21:16 +08:00
# if ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
map_fd = - 1 ;
snprintf ( mem_file , sizeof ( mem_file ) , " %s/zm.mmap.%d " , config . path_map , id ) ;
2008-07-14 23:21:16 +08:00
# else // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
shm_id = 0 ;
2008-07-14 23:21:16 +08:00
# endif // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
mem_size = 0 ;
mem_ptr = 0 ;
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
last_event = 0 ;
last_state = IDLE ;
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
last_connect_time = 0 ;
connected = false ;
2006-01-23 02:31:55 +08:00
}
Monitor : : MonitorLink : : ~ MonitorLink ( )
{
2016-04-04 22:11:48 +08:00
disconnect ( ) ;
2006-01-23 02:31:55 +08:00
}
bool Monitor : : MonitorLink : : connect ( )
{
2016-04-04 22:11:48 +08:00
if ( ! last_connect_time | | ( time ( 0 ) - last_connect_time ) > 60 )
{
last_connect_time = time ( 0 ) ;
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
mem_size = sizeof ( SharedData ) + sizeof ( TriggerData ) ;
2008-07-14 23:21:16 +08:00
2016-04-04 22:11:48 +08:00
Debug ( 1 , " link.mem.size=%d " , mem_size ) ;
2008-07-14 23:21:16 +08:00
# if ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
map_fd = open ( mem_file , O_RDWR , ( mode_t ) 0600 ) ;
if ( map_fd < 0 )
{
Debug ( 3 , " Can't open linked memory map file %s: %s " , mem_file , strerror ( errno ) ) ;
disconnect ( ) ;
return ( false ) ;
}
while ( map_fd < = 2 ) {
int new_map_fd = dup ( map_fd ) ;
Warning ( " Got one of the stdio fds for our mmap handle. map_fd was %d, new one is %d " , map_fd , new_map_fd ) ;
close ( map_fd ) ;
map_fd = new_map_fd ;
}
2008-07-14 23:21:16 +08:00
2016-04-04 22:11:48 +08:00
struct stat map_stat ;
if ( fstat ( map_fd , & map_stat ) < 0 )
{
Error ( " Can't stat linked memory map file %s: %s " , mem_file , strerror ( errno ) ) ;
disconnect ( ) ;
return ( false ) ;
}
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
if ( map_stat . st_size = = 0 )
{
Error ( " Linked memory map file %s is empty: %s " , mem_file , strerror ( errno ) ) ;
disconnect ( ) ;
return ( false ) ;
}
else if ( map_stat . st_size < mem_size )
{
Error ( " Got unexpected memory map file size %ld, expected %d " , map_stat . st_size , mem_size ) ;
disconnect ( ) ;
return ( false ) ;
}
mem_ptr = ( unsigned char * ) mmap ( NULL , mem_size , PROT_READ | PROT_WRITE , MAP_SHARED , map_fd , 0 ) ;
if ( mem_ptr = = MAP_FAILED )
{
Error ( " Can't map file %s (%d bytes) to memory: %s " , mem_file , mem_size , strerror ( errno ) ) ;
disconnect ( ) ;
return ( false ) ;
}
2008-07-14 23:21:16 +08:00
# else // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
shm_id = shmget ( ( config . shm_key & 0xffff0000 ) | id , mem_size , 0700 ) ;
if ( shm_id < 0 )
{
Debug ( 3 , " Can't shmget link memory: %s " , strerror ( errno ) ) ;
connected = false ;
return ( false ) ;
}
mem_ptr = ( unsigned char * ) shmat ( shm_id , 0 , 0 ) ;
if ( mem_ptr < 0 )
{
Debug ( 3 , " Can't shmat link memory: %s " , strerror ( errno ) ) ;
connected = false ;
return ( false ) ;
}
2008-07-14 23:21:16 +08:00
# endif // ZM_MEM_MAPPED
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
shared_data = ( SharedData * ) mem_ptr ;
trigger_data = ( TriggerData * ) ( ( char * ) shared_data + sizeof ( SharedData ) ) ;
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
if ( ! shared_data - > valid )
{
Debug ( 3 , " Linked memory not initialised by capture daemon " ) ;
disconnect ( ) ;
return ( false ) ;
}
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
last_state = shared_data - > state ;
last_event = shared_data - > last_event ;
connected = true ;
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
return ( true ) ;
}
return ( false ) ;
2006-01-23 02:31:55 +08:00
}
bool Monitor : : MonitorLink : : disconnect ( )
{
2016-04-04 22:11:48 +08:00
if ( connected )
{
connected = false ;
2006-01-23 02:31:55 +08:00
2008-07-14 23:21:16 +08:00
# if ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
if ( mem_ptr > 0 )
{
msync ( mem_ptr , mem_size , MS_ASYNC ) ;
munmap ( mem_ptr , mem_size ) ;
}
if ( map_fd > = 0 )
close ( map_fd ) ;
2008-07-14 23:21:16 +08:00
2016-04-04 22:11:48 +08:00
map_fd = - 1 ;
2008-07-14 23:21:16 +08:00
# else // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
struct shmid_ds shm_data ;
if ( shmctl ( shm_id , IPC_STAT , & shm_data ) < 0 )
{
Debug ( 3 , " Can't shmctl: %s " , strerror ( errno ) ) ;
return ( false ) ;
}
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
shm_id = 0 ;
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
if ( shm_data . shm_nattch < = 1 )
{
if ( shmctl ( shm_id , IPC_RMID , 0 ) < 0 )
{
Debug ( 3 , " Can't shmctl: %s " , strerror ( errno ) ) ;
return ( false ) ;
}
}
2006-01-23 02:31:55 +08:00
2016-04-04 22:11:48 +08:00
if ( shmdt ( mem_ptr ) < 0 )
{
Debug ( 3 , " Can't shmdt: %s " , strerror ( errno ) ) ;
return ( false ) ;
}
2006-01-23 02:31:55 +08:00
2008-07-14 23:21:16 +08:00
# endif // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
mem_size = 0 ;
mem_ptr = 0 ;
}
return ( true ) ;
2006-01-23 02:31:55 +08:00
}
bool Monitor : : MonitorLink : : isAlarmed ( )
{
2016-04-04 22:11:48 +08:00
if ( ! connected )
{
return ( false ) ;
}
return ( shared_data - > state = = ALARM ) ;
2006-01-23 02:31:55 +08:00
}
bool Monitor : : MonitorLink : : inAlarm ( )
{
2016-04-04 22:11:48 +08:00
if ( ! connected )
{
return ( false ) ;
}
return ( shared_data - > state = = ALARM | | shared_data - > state = = ALERT ) ;
2006-01-23 02:31:55 +08:00
}
bool Monitor : : MonitorLink : : hasAlarmed ( )
{
2016-04-04 22:11:48 +08:00
if ( shared_data - > state = = ALARM )
{
return ( true ) ;
}
else if ( shared_data - > last_event ! = ( unsigned int ) last_event )
{
last_event = shared_data - > last_event ;
}
return ( false ) ;
2006-01-23 02:31:55 +08:00
}
2003-09-23 17:52:45 +08:00
Monitor : : Monitor (
2016-04-04 22:11:48 +08:00
int p_id ,
const char * p_name ,
const unsigned int p_server_id ,
int p_function ,
bool p_enabled ,
const char * p_linked_monitors ,
Camera * p_camera ,
int p_orientation ,
unsigned int p_deinterlacing ,
2016-04-30 20:27:10 +08:00
int p_savejpegs ,
int p_videowriter ,
std : : string p_encoderparams ,
bool p_record_audio ,
2016-04-04 22:11:48 +08:00
const char * p_event_prefix ,
const char * p_label_format ,
const Coord & p_label_coord ,
int p_label_size ,
int p_image_buffer_count ,
int p_warmup_count ,
int p_pre_event_count ,
int p_post_event_count ,
int p_stream_replay_buffer ,
int p_alarm_frame_count ,
int p_section_length ,
int p_frame_skip ,
int p_motion_frame_skip ,
double p_analysis_fps ,
unsigned int p_analysis_update_delay ,
int p_capture_delay ,
int p_alarm_capture_delay ,
int p_fps_report_interval ,
int p_ref_blend_perc ,
int p_alarm_ref_blend_perc ,
bool p_track_motion ,
Rgb p_signal_check_colour ,
bool p_embed_exif ,
Purpose p_purpose ,
int p_n_zones ,
Zone * p_zones [ ]
2003-09-23 17:52:45 +08:00
) : id ( p_id ) ,
2016-04-04 22:11:48 +08:00
server_id ( p_server_id ) ,
function ( ( Function ) p_function ) ,
enabled ( p_enabled ) ,
width ( ( p_orientation = = ROTATE_90 | | p_orientation = = ROTATE_270 ) ? p_camera - > Height ( ) : p_camera - > Width ( ) ) ,
height ( ( p_orientation = = ROTATE_90 | | p_orientation = = ROTATE_270 ) ? p_camera - > Width ( ) : p_camera - > Height ( ) ) ,
orientation ( ( Orientation ) p_orientation ) ,
deinterlacing ( p_deinterlacing ) ,
2016-04-30 20:27:10 +08:00
savejpegspref ( p_savejpegs ) ,
videowriterpref ( p_videowriter ) ,
encoderparams ( p_encoderparams ) ,
record_audio ( p_record_audio ) ,
2016-04-04 22:11:48 +08:00
label_coord ( p_label_coord ) ,
label_size ( p_label_size ) ,
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 ) ,
stream_replay_buffer ( p_stream_replay_buffer ) ,
section_length ( p_section_length ) ,
frame_skip ( p_frame_skip ) ,
motion_frame_skip ( p_motion_frame_skip ) ,
analysis_fps ( p_analysis_fps ) ,
analysis_update_delay ( p_analysis_update_delay ) ,
capture_delay ( p_capture_delay ) ,
alarm_capture_delay ( p_alarm_capture_delay ) ,
alarm_frame_count ( p_alarm_frame_count ) ,
fps_report_interval ( p_fps_report_interval ) ,
ref_blend_perc ( p_ref_blend_perc ) ,
alarm_ref_blend_perc ( p_alarm_ref_blend_perc ) ,
track_motion ( p_track_motion ) ,
signal_check_colour ( p_signal_check_colour ) ,
embed_exif ( p_embed_exif ) ,
delta_image ( width , height , ZM_COLOUR_GRAY8 , ZM_SUBPIX_ORDER_NONE ) ,
ref_image ( width , height , p_camera - > Colours ( ) , p_camera - > SubpixelOrder ( ) ) ,
purpose ( p_purpose ) ,
last_motion_score ( 0 ) ,
camera ( p_camera ) ,
n_zones ( p_n_zones ) ,
zones ( p_zones ) ,
timestamps ( 0 ) ,
images ( 0 ) ,
privacy_bitmask ( NULL )
2003-03-26 19:57:29 +08:00
{
2016-04-04 22:11:48 +08:00
strncpy ( name , p_name , sizeof ( name ) - 1 ) ;
2003-03-26 19:57:29 +08:00
2016-04-04 22:11:48 +08:00
strncpy ( event_prefix , p_event_prefix , sizeof ( event_prefix ) - 1 ) ;
strncpy ( label_format , p_label_format , sizeof ( label_format ) - 1 ) ;
2003-03-26 19:57:29 +08:00
2016-04-04 22:11:48 +08:00
// Change \n to actual line feeds
char * token_ptr = label_format ;
const char * token_string = " \n " ;
while ( ( token_ptr = strstr ( token_ptr , token_string ) ) )
{
if ( * ( token_ptr + 1 ) )
2006-11-16 19:34:53 +08:00
{
2016-04-04 22:11:48 +08:00
* token_ptr = ' \n ' ;
token_ptr + + ;
strcpy ( token_ptr , token_ptr + 1 ) ;
2006-11-16 19:34:53 +08:00
}
2008-09-25 19:18:55 +08:00
else
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
* token_ptr = ' \0 ' ;
break ;
}
}
2016-04-06 05:14:46 +08:00
/* Parse encoder parameters */
ParseEncoderParameters ( encoderparams . c_str ( ) , & encoderparamsvec ) ;
2016-04-04 22:11:48 +08:00
fps = 0.0 ;
event_count = 0 ;
image_count = 0 ;
ready_count = warmup_count ;
first_alarm_count = 0 ;
last_alarm_count = 0 ;
state = IDLE ;
if ( alarm_frame_count < 1 )
alarm_frame_count = 1 ;
else if ( alarm_frame_count > MAX_PRE_ALARM_FRAMES )
alarm_frame_count = MAX_PRE_ALARM_FRAMES ;
auto_resume_time = 0 ;
if ( strcmp ( config . event_close_mode , " time " ) = = 0 )
event_close_mode = CLOSE_TIME ;
else if ( strcmp ( config . event_close_mode , " alarm " ) = = 0 )
event_close_mode = CLOSE_ALARM ;
else
event_close_mode = CLOSE_IDLE ;
Debug ( 1 , " monitor purpose=%d " , purpose ) ;
mem_size = sizeof ( SharedData )
+ sizeof ( TriggerData )
2016-04-30 20:27:10 +08:00
+ sizeof ( VideoStoreData ) //Information to pass back to the capture process
2016-04-04 22:11:48 +08:00
+ ( image_buffer_count * sizeof ( struct timeval ) )
+ ( image_buffer_count * camera - > ImageSize ( ) )
+ 64 ; /* Padding used to permit aligning the images buffer to 16 byte boundary */
Debug ( 1 , " mem.size=%d " , mem_size ) ;
mem_ptr = NULL ;
if ( purpose = = CAPTURE ) {
this - > connect ( ) ;
if ( ! mem_ptr ) exit ( - 1 ) ;
memset ( mem_ptr , 0 , mem_size ) ;
shared_data - > size = sizeof ( SharedData ) ;
shared_data - > active = enabled ;
shared_data - > signal = false ;
shared_data - > state = IDLE ;
shared_data - > last_write_index = image_buffer_count ;
shared_data - > last_read_index = image_buffer_count ;
shared_data - > last_write_time = 0 ;
shared_data - > last_event = 0 ;
shared_data - > action = ( Action ) 0 ;
shared_data - > brightness = - 1 ;
shared_data - > hue = - 1 ;
shared_data - > colour = - 1 ;
shared_data - > contrast = - 1 ;
shared_data - > alarm_x = - 1 ;
shared_data - > alarm_y = - 1 ;
shared_data - > format = camera - > SubpixelOrder ( ) ;
shared_data - > imagesize = camera - > ImageSize ( ) ;
trigger_data - > size = sizeof ( TriggerData ) ;
trigger_data - > trigger_state = TRIGGER_CANCEL ;
trigger_data - > trigger_score = 0 ;
trigger_data - > trigger_cause [ 0 ] = 0 ;
trigger_data - > trigger_text [ 0 ] = 0 ;
trigger_data - > trigger_showtext [ 0 ] = 0 ;
shared_data - > valid = true ;
2016-04-30 20:27:10 +08:00
video_store_data - > recording = false ;
snprintf ( video_store_data - > event_file , sizeof ( video_store_data - > event_file ) , " nothing " ) ;
video_store_data - > size = sizeof ( VideoStoreData ) ;
//video_store_data->frameNumber = 0;
2016-04-04 22:11:48 +08:00
} else if ( purpose = = ANALYSIS ) {
this - > connect ( ) ;
if ( ! mem_ptr ) exit ( - 1 ) ;
shared_data - > state = IDLE ;
shared_data - > last_read_time = 0 ;
shared_data - > alarm_x = - 1 ;
shared_data - > alarm_y = - 1 ;
}
if ( ( ! mem_ptr ) | | ! shared_data - > valid )
{
if ( purpose ! = QUERY )
{
Error ( " Shared data not initialised by capture daemon for monitor %s " , name ) ;
exit ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
// Will this not happen every time a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after..
2016-04-06 05:14:46 +08:00
// In my storage areas branch, I took this out.. and didn't notice any problems.
2016-04-04 22:11:48 +08:00
if ( ! n_zones ) {
Debug ( 1 , " Monitor %s has no zones, adding one. " , name ) ;
n_zones = 1 ;
zones = new Zone * [ 1 ] ;
Coord coords [ 4 ] = { Coord ( 0 , 0 ) , Coord ( width - 1 , 0 ) , Coord ( width - 1 , height - 1 ) , Coord ( 0 , height - 1 ) } ;
zones [ 0 ] = new Zone ( this , 0 , " All " , Zone : : ACTIVE , Polygon ( sizeof ( coords ) / sizeof ( * coords ) , coords ) , RGB_RED , Zone : : BLOBS ) ;
}
start_time = last_fps_time = time ( 0 ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
event = 0 ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
Debug ( 1 , " Monitor %s has function %d " , name , function ) ;
Debug ( 1 , " Monitor %s LBF = '%s', LBX = %d, LBY = %d, LBS = %d " , name , label_format , label_coord . X ( ) , label_coord . Y ( ) , label_size ) ;
Debug ( 1 , " Monitor %s IBC = %d, WUC = %d, pEC = %d, PEC = %d, EAF = %d, FRI = %d, RBP = %d, ARBP = %d, FM = %d " , name , image_buffer_count , warmup_count , pre_event_count , post_event_count , alarm_frame_count , fps_report_interval , ref_blend_perc , alarm_ref_blend_perc , track_motion ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( purpose = = ANALYSIS )
{
static char path [ PATH_MAX ] ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
strncpy ( path , config . dir_events , sizeof ( path ) ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +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 ) ) ;
}
}
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
snprintf ( path , sizeof ( path ) , " %s/%d " , config . dir_events , id ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +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 ) ) ;
}
char temp_path [ PATH_MAX ] ;
snprintf ( temp_path , sizeof ( temp_path ) , " %d " , id ) ;
if ( chdir ( config . dir_events ) < 0 )
Fatal ( " Can't change directory to '%s': %s " , config . dir_events , strerror ( errno ) ) ;
if ( symlink ( temp_path , name ) < 0 )
Fatal ( " Can't symlink '%s' to '%s': %s " , temp_path , name , strerror ( errno ) ) ;
if ( chdir ( " .. " ) < 0 )
Fatal ( " Can't change to parent directory: %s " , strerror ( errno ) ) ;
}
while ( shared_data - > last_write_index = = ( unsigned int ) image_buffer_count
& & shared_data - > last_write_time = = 0 )
{
Warning ( " Waiting for capture daemon " ) ;
sleep ( 1 ) ;
}
ref_image . Assign ( width , height , camera - > Colours ( ) , camera - > SubpixelOrder ( ) , image_buffer [ shared_data - > last_write_index ] . image - > Buffer ( ) , camera - > ImageSize ( ) ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
n_linked_monitors = 0 ;
linked_monitors = 0 ;
2015-07-24 04:36:30 +08:00
2016-04-04 22:11:48 +08:00
adaptive_skip = true ;
2015-07-24 04:36:30 +08:00
2016-04-04 22:11:48 +08:00
ReloadLinkedMonitors ( p_linked_monitors ) ;
}
2003-03-26 19:57:29 +08:00
}
2014-06-27 02:54:47 +08:00
bool Monitor : : connect ( ) {
# if ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
snprintf ( mem_file , sizeof ( mem_file ) , " %s/zm.mmap.%d " , config . path_map , id ) ;
map_fd = open ( mem_file , O_RDWR | O_CREAT , ( mode_t ) 0600 ) ;
if ( map_fd < 0 )
Fatal ( " Can't open memory map file %s, probably not enough space free: %s " , mem_file , strerror ( errno ) ) ;
struct stat map_stat ;
if ( fstat ( map_fd , & map_stat ) < 0 )
Fatal ( " Can't stat memory map file %s: %s, is the zmc process for this monitor running? " , mem_file , strerror ( errno ) ) ;
if ( map_stat . st_size ! = mem_size & & purpose = = CAPTURE ) {
// Allocate the size
if ( ftruncate ( map_fd , mem_size ) < 0 ) {
Fatal ( " Can't extend memory map file %s to %d bytes: %s " , mem_file , mem_size , strerror ( errno ) ) ;
}
} else if ( map_stat . st_size = = 0 ) {
Error ( " Got empty memory map file size %ld, is the zmc process for this monitor running? " , map_stat . st_size , mem_size ) ;
return false ;
} else if ( map_stat . st_size ! = mem_size ) {
Error ( " Got unexpected memory map file size %ld, expected %d " , map_stat . st_size , mem_size ) ;
return false ;
} else {
2015-04-21 00:53:02 +08:00
# ifdef MAP_LOCKED
2016-04-04 22:11:48 +08:00
mem_ptr = ( unsigned char * ) mmap ( NULL , mem_size , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_LOCKED , map_fd , 0 ) ;
if ( mem_ptr = = MAP_FAILED ) {
if ( errno = = EAGAIN ) {
Debug ( 1 , " Unable to map file %s (%d bytes) to locked memory, trying unlocked " , mem_file , mem_size ) ;
2015-04-21 00:53:02 +08:00
# endif
2016-04-04 22:11:48 +08:00
mem_ptr = ( unsigned char * ) mmap ( NULL , mem_size , PROT_READ | PROT_WRITE , MAP_SHARED , map_fd , 0 ) ;
Debug ( 1 , " Mapped file %s (%d bytes) to locked memory, unlocked " , mem_file , mem_size ) ;
2015-04-21 00:53:02 +08:00
# ifdef MAP_LOCKED
2016-04-04 22:11:48 +08:00
}
2014-06-27 02:54:47 +08:00
}
2015-04-21 00:53:02 +08:00
# endif
2016-04-04 22:11:48 +08:00
if ( mem_ptr = = MAP_FAILED )
Fatal ( " Can't map file %s (%d bytes) to memory: %s(%d) " , mem_file , mem_size , strerror ( errno ) , errno ) ;
}
2014-06-27 02:54:47 +08:00
# else // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
shm_id = shmget ( ( config . shm_key & 0xffff0000 ) | id , mem_size , IPC_CREAT | 0700 ) ;
if ( shm_id < 0 ) {
Error ( " Can't shmget, probably not enough shared memory space free: %s " , strerror ( errno ) ) ;
exit ( - 1 ) ;
}
mem_ptr = ( unsigned char * ) shmat ( shm_id , 0 , 0 ) ;
if ( mem_ptr < 0 )
{
Error ( " Can't shmat: %s " , strerror ( errno ) ) ;
exit ( - 1 ) ;
}
2014-06-27 02:54:47 +08:00
# endif // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
shared_data = ( SharedData * ) mem_ptr ;
trigger_data = ( TriggerData * ) ( ( char * ) shared_data + sizeof ( SharedData ) ) ;
2016-04-30 20:27:10 +08:00
video_store_data = ( VideoStoreData * ) ( ( char * ) trigger_data + sizeof ( TriggerData ) ) ;
struct timeval * shared_timestamps = ( struct timeval * ) ( ( char * ) video_store_data + sizeof ( VideoStoreData ) ) ;
2016-04-04 22:11:48 +08:00
unsigned char * shared_images = ( unsigned char * ) ( ( char * ) shared_timestamps + ( image_buffer_count * sizeof ( struct timeval ) ) ) ;
if ( ( ( unsigned long ) shared_images % 16 ) ! = 0 ) {
/* Align images buffer to nearest 16 byte boundary */
Debug ( 3 , " Aligning shared memory images to the next 16 byte boundary " ) ;
shared_images = ( uint8_t * ) ( ( unsigned long ) shared_images + ( 16 - ( ( unsigned long ) shared_images % 16 ) ) ) ;
}
image_buffer = new Snapshot [ image_buffer_count ] ;
for ( int i = 0 ; i < image_buffer_count ; i + + )
{
image_buffer [ i ] . timestamp = & ( shared_timestamps [ i ] ) ;
image_buffer [ i ] . image = new Image ( width , height , camera - > Colours ( ) , camera - > SubpixelOrder ( ) , & ( shared_images [ i * camera - > ImageSize ( ) ] ) ) ;
image_buffer [ i ] . image - > HoldBuffer ( true ) ; /* Don't release the internal buffer or replace it with another */
}
if ( ( deinterlacing & 0xff ) = = 4 )
{
/* Four field motion adaptive deinterlacing in use */
/* Allocate a buffer for the next image */
next_buffer . image = new Image ( width , height , camera - > Colours ( ) , camera - > SubpixelOrder ( ) ) ;
next_buffer . timestamp = new struct timeval ;
}
if ( ( purpose = = ANALYSIS ) & & analysis_fps )
{
// Size of pre event buffer must be greater than pre_event_count
// if alarm_frame_count > 1, because in this case the buffer contains
// alarmed images that must be discarded when event is created
pre_event_buffer_count = pre_event_count + alarm_frame_count - 1 ;
pre_event_buffer = new Snapshot [ pre_event_buffer_count ] ;
for ( int i = 0 ; i < pre_event_buffer_count ; i + + )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
pre_event_buffer [ i ] . timestamp = new struct timeval ;
pre_event_buffer [ i ] . image = new Image ( width , height , camera - > Colours ( ) , camera - > SubpixelOrder ( ) ) ;
2014-06-27 02:54:47 +08:00
}
2016-04-04 22:11:48 +08:00
}
return true ;
2014-06-27 02:54:47 +08:00
}
Monitor : : ~ Monitor ( )
{
2016-04-04 22:11:48 +08:00
if ( timestamps ) {
delete [ ] timestamps ;
timestamps = 0 ;
}
if ( images ) {
delete [ ] images ;
images = 0 ;
}
if ( privacy_bitmask ) {
delete [ ] privacy_bitmask ;
privacy_bitmask = NULL ;
}
if ( mem_ptr ) {
if ( event )
Info ( " %s: %03d - Closing event %d, shutting down " , name , image_count , event - > Id ( ) ) ;
closeEvent ( ) ;
2014-06-27 02:54:47 +08:00
if ( ( deinterlacing & 0xff ) = = 4 )
{
2016-04-04 22:11:48 +08:00
delete next_buffer . image ;
delete next_buffer . timestamp ;
}
for ( int i = 0 ; i < image_buffer_count ; i + + )
{
delete image_buffer [ i ] . image ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
delete [ ] image_buffer ;
} // end if mem_ptr
for ( int i = 0 ; i < n_zones ; i + + )
{
delete zones [ i ] ;
}
delete [ ] zones ;
delete camera ;
2015-07-27 22:24:32 +08:00
2016-04-04 22:11:48 +08:00
if ( mem_ptr ) {
if ( purpose = = ANALYSIS )
2015-07-27 22:24:32 +08:00
{
2016-04-04 22:11:48 +08:00
shared_data - > state = state = IDLE ;
shared_data - > last_read_index = image_buffer_count ;
shared_data - > last_read_time = 0 ;
if ( analysis_fps )
{
2015-07-27 22:24:32 +08:00
for ( int i = 0 ; i < pre_event_buffer_count ; i + + )
{
2016-04-04 22:11:48 +08:00
delete pre_event_buffer [ i ] . image ;
delete pre_event_buffer [ i ] . timestamp ;
2015-07-27 22:24:32 +08:00
}
2016-04-04 22:11:48 +08:00
delete [ ] pre_event_buffer ;
}
2015-07-27 22:24:32 +08:00
}
2016-04-04 22:11:48 +08:00
else if ( purpose = = CAPTURE )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
shared_data - > valid = false ;
memset ( mem_ptr , 0 , mem_size ) ;
}
2006-01-23 02:31:55 +08:00
2008-07-14 23:21:16 +08:00
# if ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
if ( msync ( mem_ptr , mem_size , MS_SYNC ) < 0 )
Error ( " Can't msync: %s " , strerror ( errno ) ) ;
if ( munmap ( mem_ptr , mem_size ) < 0 )
Fatal ( " Can't munmap: %s " , strerror ( errno ) ) ;
close ( map_fd ) ;
2008-07-14 23:21:16 +08:00
# else // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
struct shmid_ds shm_data ;
if ( shmctl ( shm_id , IPC_STAT , & shm_data ) < 0 ) {
Error ( " Can't shmctl: %s " , strerror ( errno ) ) ;
exit ( - 1 ) ;
}
if ( shm_data . shm_nattch < = 1 ) {
if ( shmctl ( shm_id , IPC_RMID , 0 ) < 0 ) {
Error ( " Can't shmctl: %s " , strerror ( errno ) ) ;
exit ( - 1 ) ;
}
}
2008-07-14 23:21:16 +08:00
# endif // ZM_MEM_MAPPED
2016-04-04 22:11:48 +08:00
} // end if mem_ptr
2006-01-23 02:31:55 +08:00
}
2003-03-26 19:57:29 +08:00
void Monitor : : AddZones ( int p_n_zones , Zone * p_zones [ ] )
{
2016-04-04 22:11:48 +08:00
for ( int i = 0 ; i < n_zones ; i + + )
delete zones [ i ] ;
delete [ ] zones ;
n_zones = p_n_zones ;
zones = p_zones ;
2003-03-26 19:57:29 +08:00
}
2015-08-20 23:37:59 +08:00
void Monitor : : AddPrivacyBitmask ( Zone * p_zones [ ] )
2015-08-20 20:20:41 +08:00
{
2016-04-04 22:11:48 +08:00
if ( privacy_bitmask )
delete [ ] privacy_bitmask ;
privacy_bitmask = NULL ;
Image * privacy_image = NULL ;
for ( int i = 0 ; i < n_zones ; i + + )
{
if ( p_zones [ i ] - > IsPrivacy ( ) )
2015-09-16 22:51:27 +08:00
{
2016-04-04 22:11:48 +08:00
if ( ! privacy_image )
{
privacy_image = new Image ( width , height , 1 , ZM_SUBPIX_ORDER_NONE ) ;
privacy_image - > Clear ( ) ;
}
privacy_image - > Fill ( 0xff , p_zones [ i ] - > GetPolygon ( ) ) ;
privacy_image - > Outline ( 0xff , p_zones [ i ] - > GetPolygon ( ) ) ;
}
} // end foreach zone
if ( privacy_image )
privacy_bitmask = privacy_image - > Buffer ( ) ;
2015-08-20 20:20:41 +08:00
}
2003-03-26 19:57:29 +08:00
Monitor : : State Monitor : : GetState ( ) const
{
2016-04-04 22:11:48 +08:00
return ( ( State ) shared_data - > state ) ;
2003-03-26 19:57:29 +08:00
}
2015-06-04 03:10:52 +08:00
int Monitor : : GetImage ( int index , int scale )
2003-03-26 19:57:29 +08:00
{
2016-04-04 22:11:48 +08:00
if ( index < 0 | | index > image_buffer_count )
{
index = shared_data - > last_write_index ;
}
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( index ! = image_buffer_count )
{
Image * image ;
// If we are going to be modifying the snapshot before writing, then we need to copy it
if ( ( scale ! = ZM_SCALE_BASE ) | | ( ! config . timestamp_on_capture ) ) {
Snapshot * snap = & image_buffer [ index ] ;
Image * snap_image = snap - > image ;
2015-06-04 03:10:52 +08:00
2016-04-04 22:11:48 +08:00
alarm_image . Assign ( * snap_image ) ;
2015-06-04 03:10:52 +08:00
2016-04-04 22:11:48 +08:00
//write_image.Assign( *snap_image );
2015-06-04 03:10:52 +08:00
2016-04-04 22:11:48 +08:00
if ( scale ! = ZM_SCALE_BASE ) {
alarm_image . Scale ( scale ) ;
}
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( ! config . timestamp_on_capture ) {
TimestampImage ( & alarm_image , snap - > timestamp ) ;
}
image = & alarm_image ;
} else {
image = image_buffer [ index ] . image ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
static char filename [ PATH_MAX ] ;
snprintf ( filename , sizeof ( filename ) , " Monitor%d.jpg " , id ) ;
image - > WriteJpeg ( filename ) ;
}
else
{
Error ( " Unable to generate image, no images in buffer " ) ;
}
return ( 0 ) ;
2003-03-26 19:57:29 +08:00
}
struct timeval Monitor : : GetTimestamp ( int index ) const
{
2016-04-04 22:11:48 +08:00
if ( index < 0 | | index > image_buffer_count )
{
index = shared_data - > last_write_index ;
}
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( index ! = image_buffer_count )
{
Snapshot * snap = & image_buffer [ index ] ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
return ( * ( snap - > timestamp ) ) ;
}
else
{
static struct timeval null_tv = { 0 , 0 } ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
return ( null_tv ) ;
}
2003-03-26 19:57:29 +08:00
}
unsigned int Monitor : : GetLastReadIndex ( ) const
{
2016-04-04 22:11:48 +08:00
return ( shared_data - > last_read_index ! = ( unsigned int ) image_buffer_count ? shared_data - > last_read_index : - 1 ) ;
2003-03-26 19:57:29 +08:00
}
unsigned int Monitor : : GetLastWriteIndex ( ) const
{
2016-04-04 22:11:48 +08:00
return ( shared_data - > last_write_index ! = ( unsigned int ) image_buffer_count ? shared_data - > last_write_index : - 1 ) ;
2003-03-26 19:57:29 +08:00
}
unsigned int Monitor : : GetLastEvent ( ) const
{
2016-04-04 22:11:48 +08:00
return ( shared_data - > last_event ) ;
2003-03-26 19:57:29 +08:00
}
double Monitor : : GetFPS ( ) const
{
2016-04-04 22:11:48 +08:00
int index1 = shared_data - > last_write_index ;
if ( index1 = = image_buffer_count )
{
return ( 0.0 ) ;
}
Snapshot * snap1 = & image_buffer [ index1 ] ;
if ( ! snap1 - > timestamp | | ! snap1 - > timestamp - > tv_sec )
{
return ( 0.0 ) ;
}
struct timeval time1 = * snap1 - > timestamp ;
int image_count = image_buffer_count ;
int index2 = ( index1 + 1 ) % image_buffer_count ;
if ( index2 = = image_buffer_count )
{
return ( 0.0 ) ;
}
Snapshot * snap2 = & image_buffer [ index2 ] ;
while ( ! snap2 - > timestamp | | ! snap2 - > timestamp - > tv_sec )
{
if ( index1 = = index2 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
return ( 0.0 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
index2 = ( index2 + 1 ) % image_buffer_count ;
snap2 = & image_buffer [ index2 ] ;
image_count - - ;
}
struct timeval time2 = * snap2 - > timestamp ;
2003-03-26 19:57:29 +08:00
2016-04-04 22:11:48 +08:00
double time_diff = tvDiffSec ( time2 , time1 ) ;
2008-07-16 16:35:59 +08:00
2016-04-04 22:11:48 +08:00
double curr_fps = image_count / time_diff ;
2003-03-26 19:57:29 +08:00
2016-04-04 22:11:48 +08:00
if ( curr_fps < 0.0 )
{
//Error( "Negative FPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d", curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count );
return ( 0.0 ) ;
}
return ( curr_fps ) ;
2003-03-26 19:57:29 +08:00
}
2015-07-24 04:36:30 +08:00
useconds_t Monitor : : GetAnalysisRate ( )
{
2016-04-04 22:11:48 +08:00
double capturing_fps = GetFPS ( ) ;
if ( ! analysis_fps )
{
return ( 0 ) ;
}
else if ( analysis_fps > capturing_fps )
{
Warning ( " Analysis fps (%.2f) is greater than capturing fps (%.2f) " , analysis_fps , capturing_fps ) ;
return ( 0 ) ;
}
else
{
return ( ( 1000000 / analysis_fps ) - ( 1000000 / capturing_fps ) ) ;
}
2015-07-24 04:36:30 +08:00
}
void Monitor : : UpdateAdaptiveSkip ( )
{
2016-04-04 22:11:48 +08:00
if ( config . opt_adaptive_skip )
{
double capturing_fps = GetFPS ( ) ;
if ( adaptive_skip & & analysis_fps & & ( analysis_fps < capturing_fps ) )
2015-07-24 04:36:30 +08:00
{
2016-04-04 22:11:48 +08:00
Info ( " Analysis fps (%.2f) is lower than capturing fps (%.2f), disabling adaptive skip feature " , analysis_fps , capturing_fps ) ;
adaptive_skip = false ;
2015-07-24 04:36:30 +08:00
}
2016-04-04 22:11:48 +08:00
else if ( ! adaptive_skip & & ( ! analysis_fps | | ( analysis_fps > = capturing_fps ) ) )
2015-07-24 04:36:30 +08:00
{
2016-04-04 22:11:48 +08:00
Info ( " Enabling adaptive skip feature " ) ;
adaptive_skip = true ;
}
}
else
{
adaptive_skip = false ;
}
2015-07-24 04:36:30 +08:00
}
2004-12-29 01:41:55 +08:00
void Monitor : : ForceAlarmOn ( int force_score , const char * force_cause , const char * force_text )
2003-03-26 19:57:29 +08:00
{
2016-04-04 22:11:48 +08:00
trigger_data - > trigger_state = TRIGGER_ON ;
trigger_data - > trigger_score = force_score ;
strncpy ( trigger_data - > trigger_cause , force_cause , sizeof ( trigger_data - > trigger_cause ) ) ;
strncpy ( trigger_data - > trigger_text , force_text , sizeof ( trigger_data - > trigger_text ) ) ;
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
{
2016-04-04 22:11:48 +08:00
trigger_data - > trigger_state = TRIGGER_OFF ;
2003-03-26 21:18:26 +08:00
}
void Monitor : : CancelForced ( )
{
2016-04-04 22:11:48 +08:00
trigger_data - > trigger_state = TRIGGER_CANCEL ;
2003-03-26 19:57:29 +08:00
}
2005-12-23 00:46:25 +08:00
void Monitor : : actionReload ( )
{
2016-04-04 22:11:48 +08:00
shared_data - > action | = RELOAD ;
2005-12-23 00:46:25 +08:00
}
void Monitor : : actionEnable ( )
{
2016-04-04 22:11:48 +08:00
shared_data - > action | = RELOAD ;
static char sql [ ZM_SQL_SML_BUFSIZ ] ;
snprintf ( sql , sizeof ( sql ) , " update Monitors set Enabled = 1 where Id = '%d' " , id ) ;
if ( mysql_query ( & dbconn , sql ) )
{
Error ( " Can't run query: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
2005-12-23 00:46:25 +08:00
}
void Monitor : : actionDisable ( )
{
2016-04-04 22:11:48 +08:00
shared_data - > action | = RELOAD ;
static char sql [ ZM_SQL_SML_BUFSIZ ] ;
snprintf ( sql , sizeof ( sql ) , " update Monitors set Enabled = 0 where Id = '%d' " , id ) ;
if ( mysql_query ( & dbconn , sql ) )
{
Error ( " Can't run query: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
2005-12-23 00:46:25 +08:00
}
void Monitor : : actionSuspend ( )
2005-02-24 18:43:29 +08:00
{
2016-04-04 22:11:48 +08:00
shared_data - > action | = SUSPEND ;
2005-02-24 18:43:29 +08:00
}
2005-12-23 00:46:25 +08:00
void Monitor : : actionResume ( )
2005-02-24 18:43:29 +08:00
{
2016-04-04 22:11:48 +08:00
shared_data - > action | = RESUME ;
2005-02-24 18:43:29 +08:00
}
2005-12-23 00:46:25 +08:00
int Monitor : : actionBrightness ( int p_brightness )
2003-06-25 17:47:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( purpose ! = CAPTURE )
{
if ( p_brightness > = 0 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
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
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to set brightness " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
2009-05-08 17:47:37 +08:00
else
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to get brightness " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
return ( shared_data - > brightness ) ;
}
return ( camera - > Brightness ( p_brightness ) ) ;
2003-06-25 17:47:09 +08:00
}
2005-12-23 00:46:25 +08:00
int Monitor : : actionContrast ( int p_contrast )
2003-06-25 17:47:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( purpose ! = CAPTURE )
{
if ( p_contrast > = 0 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
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
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to set contrast " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
2009-05-08 17:47:37 +08:00
else
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to get contrast " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
return ( shared_data - > contrast ) ;
}
return ( camera - > Contrast ( p_contrast ) ) ;
2003-06-25 17:47:09 +08:00
}
2005-12-23 00:46:25 +08:00
int Monitor : : actionHue ( int p_hue )
2003-06-25 17:47:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( purpose ! = CAPTURE )
{
if ( p_hue > = 0 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
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
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to set hue " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
2009-05-08 17:47:37 +08:00
else
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to get hue " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
return ( shared_data - > hue ) ;
}
return ( camera - > Hue ( p_hue ) ) ;
2003-06-25 17:47:09 +08:00
}
2005-12-23 00:46:25 +08:00
int Monitor : : actionColour ( int p_colour )
2003-06-25 17:47:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( purpose ! = CAPTURE )
{
if ( p_colour > = 0 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
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
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to set colour " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
else
{
shared_data - > action | = GET_SETTINGS ;
int wait_loops = 10 ;
while ( shared_data - > action & GET_SETTINGS )
{
if ( wait_loops - - )
usleep ( 100000 ) ;
2009-05-08 17:47:37 +08:00
else
{
2016-04-04 22:11:48 +08:00
Warning ( " Timed out waiting to get colour " ) ;
return ( - 1 ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
return ( shared_data - > colour ) ;
}
return ( camera - > Colour ( p_colour ) ) ;
2003-06-25 17:47:09 +08:00
}
2005-11-30 01:51:06 +08:00
void Monitor : : DumpZoneImage ( const char * zone_string )
2003-03-26 19:57:29 +08:00
{
2016-04-04 22:11:48 +08:00
int exclude_id = 0 ;
int extra_colour = 0 ;
Polygon extra_zone ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( zone_string )
{
if ( ! Zone : : ParseZoneString ( zone_string , exclude_id , extra_colour , extra_zone ) )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Error ( " Failed to parse zone string, ignoring " ) ;
}
}
int index = shared_data - > last_write_index ;
Snapshot * snap = & image_buffer [ index ] ;
Image * snap_image = snap - > image ;
Image zone_image ( * snap_image ) ;
if ( zone_image . Colours ( ) = = ZM_COLOUR_GRAY8 ) {
zone_image . Colourise ( ZM_COLOUR_RGB24 , ZM_SUBPIX_ORDER_RGB ) ;
}
for ( int i = 0 ; i < n_zones ; i + + )
{
if ( exclude_id & & ( ! extra_colour | | extra_zone . getNumCoords ( ) ) & & zones [ i ] - > Id ( ) = = exclude_id )
continue ;
Rgb colour ;
if ( exclude_id & & ! extra_zone . getNumCoords ( ) & & zones [ i ] - > Id ( ) = = exclude_id )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
colour = extra_colour ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( zones [ i ] - > IsActive ( ) )
{
colour = RGB_RED ;
}
else if ( zones [ i ] - > IsInclusive ( ) )
{
colour = RGB_ORANGE ;
}
else if ( zones [ i ] - > IsExclusive ( ) )
{
colour = RGB_PURPLE ;
}
else if ( zones [ i ] - > IsPreclusive ( ) )
{
colour = RGB_BLUE ;
}
else
{
colour = RGB_WHITE ;
}
}
zone_image . Fill ( colour , 2 , zones [ i ] - > GetPolygon ( ) ) ;
zone_image . Outline ( colour , zones [ i ] - > GetPolygon ( ) ) ;
}
if ( extra_zone . getNumCoords ( ) )
{
zone_image . Fill ( extra_colour , 2 , extra_zone ) ;
zone_image . Outline ( extra_colour , extra_zone ) ;
}
static char filename [ PATH_MAX ] ;
snprintf ( filename , sizeof ( filename ) , " Zones%d.jpg " , id ) ;
zone_image . WriteJpeg ( filename ) ;
2003-03-26 19:57:29 +08:00
}
2004-01-15 05:26:47 +08:00
void Monitor : : DumpImage ( Image * dump_image ) const
2003-03-26 19:57:29 +08:00
{
2016-04-04 22:11:48 +08:00
if ( image_count & & ! ( image_count % 10 ) )
{
static char filename [ PATH_MAX ] ;
static char new_filename [ PATH_MAX ] ;
snprintf ( filename , sizeof ( filename ) , " Monitor%d.jpg " , id ) ;
snprintf ( new_filename , sizeof ( new_filename ) , " Monitor%d-new.jpg " , id ) ;
dump_image - > WriteJpeg ( new_filename ) ;
rename ( new_filename , filename ) ;
}
2003-03-26 19:57:29 +08:00
}
2006-01-15 06:47:02 +08:00
bool Monitor : : CheckSignal ( const Image * image )
{
2016-04-04 22:11:48 +08:00
static bool static_undef = true ;
/* RGB24 colors */
static uint8_t red_val ;
static uint8_t green_val ;
static uint8_t blue_val ;
static uint8_t grayscale_val ; /* 8bit grayscale color */
static Rgb colour_val ; /* RGB32 color */
static int usedsubpixorder ;
if ( config . signal_check_points > 0 )
{
if ( static_undef )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
static_undef = false ;
usedsubpixorder = camera - > SubpixelOrder ( ) ;
colour_val = rgb_convert ( signal_check_colour , ZM_SUBPIX_ORDER_BGR ) ; /* HTML colour code is actually BGR in memory, we want RGB */
colour_val = rgb_convert ( colour_val , usedsubpixorder ) ;
red_val = RED_VAL_BGRA ( signal_check_colour ) ;
green_val = GREEN_VAL_BGRA ( signal_check_colour ) ;
blue_val = BLUE_VAL_BGRA ( signal_check_colour ) ;
grayscale_val = signal_check_colour & 0xff ; /* Clear all bytes but lowest byte */
}
const uint8_t * buffer = image - > Buffer ( ) ;
int pixels = image - > Pixels ( ) ;
int width = image - > Width ( ) ;
int colours = image - > Colours ( ) ;
int index = 0 ;
for ( int i = 0 ; i < config . signal_check_points ; i + + )
{
while ( true )
{
index = ( int ) ( ( ( long long ) rand ( ) * ( long long ) ( pixels - 1 ) ) / RAND_MAX ) ;
if ( ! config . timestamp_on_capture | | ! label_format [ 0 ] )
break ;
// Avoid sampling the rows with timestamp in
if ( index < ( label_coord . Y ( ) * width ) | | index > = ( label_coord . Y ( ) + Image : : LINE_HEIGHT ) * width )
break ;
}
if ( colours = = ZM_COLOUR_GRAY8 ) {
if ( * ( buffer + index ) ! = grayscale_val )
return true ;
} else if ( colours = = ZM_COLOUR_RGB24 ) {
const uint8_t * ptr = buffer + ( index * colours ) ;
if ( usedsubpixorder = = ZM_SUBPIX_ORDER_BGR ) {
if ( ( RED_PTR_BGRA ( ptr ) ! = red_val ) | | ( GREEN_PTR_BGRA ( ptr ) ! = green_val ) | | ( BLUE_PTR_BGRA ( ptr ) ! = blue_val ) )
return true ;
} else {
/* Assume RGB */
if ( ( RED_PTR_RGBA ( ptr ) ! = red_val ) | | ( GREEN_PTR_RGBA ( ptr ) ! = green_val ) | | ( BLUE_PTR_RGBA ( ptr ) ! = blue_val ) )
return true ;
}
} else if ( colours = = ZM_COLOUR_RGB32 ) {
if ( usedsubpixorder = = ZM_SUBPIX_ORDER_ARGB | | usedsubpixorder = = ZM_SUBPIX_ORDER_ABGR ) {
if ( ARGB_ABGR_ZEROALPHA ( * ( ( ( const Rgb * ) buffer ) + index ) ) ! = ARGB_ABGR_ZEROALPHA ( colour_val ) )
return true ;
} else {
/* Assume RGBA or BGRA */
if ( RGBA_BGRA_ZEROALPHA ( * ( ( ( const Rgb * ) buffer ) + index ) ) ! = RGBA_BGRA_ZEROALPHA ( colour_val ) )
return true ;
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
return ( false ) ;
}
return ( true ) ;
2006-01-15 06:47:02 +08:00
}
2003-03-26 19:57:29 +08:00
bool Monitor : : Analyse ( )
{
2016-04-04 22:11:48 +08:00
if ( shared_data - > last_read_index = = shared_data - > last_write_index )
{
2016-04-15 00:34:52 +08:00
// I wonder how often this happens. Maybe if this happens we should sleep or something?
2016-04-04 22:11:48 +08:00
return ( false ) ;
}
struct timeval now ;
gettimeofday ( & now , NULL ) ;
if ( image_count & & fps_report_interval & & ! ( image_count % fps_report_interval ) )
{
fps = double ( fps_report_interval ) / ( now . tv_sec - last_fps_time ) ;
Info ( " %s: %d - Analysing at %.2f fps " , name , image_count , fps ) ;
last_fps_time = now . tv_sec ;
}
int index ;
if ( adaptive_skip )
{
int read_margin = shared_data - > last_read_index - shared_data - > last_write_index ;
if ( read_margin < 0 ) read_margin + = image_buffer_count ;
int step = 1 ;
2016-04-30 20:27:10 +08:00
// Isn't read_margin always > 0 here?
2016-04-04 22:11:48 +08:00
if ( read_margin > 0 )
2009-05-08 17:47:37 +08:00
{
2016-04-30 20:27:10 +08:00
// TODO explain this so... 90% of image buffer / 50% of read margin?
2016-04-04 22:11:48 +08:00
step = ( 9 * image_buffer_count ) / ( 5 * read_margin ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
int pending_frames = shared_data - > last_write_index - shared_data - > last_read_index ;
if ( pending_frames < 0 ) pending_frames + = image_buffer_count ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +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 ) ;
if ( step < = pending_frames )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
index = ( shared_data - > last_read_index + step ) % image_buffer_count ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
{
if ( pending_frames )
{
Warning ( " Approaching buffer overrun, consider slowing capture, simplifying analysis or increasing ring buffer size " ) ;
}
index = shared_data - > last_write_index % image_buffer_count ;
}
}
else
{
index = shared_data - > last_write_index % image_buffer_count ;
}
Snapshot * snap = & image_buffer [ index ] ;
struct timeval * timestamp = snap - > timestamp ;
Image * snap_image = snap - > image ;
if ( shared_data - > action )
{
if ( shared_data - > action & RELOAD )
{
Info ( " Received reload indication at count %d " , image_count ) ;
shared_data - > action & = ~ RELOAD ;
Reload ( ) ;
}
if ( shared_data - > action & SUSPEND )
{
if ( Active ( ) )
{
Info ( " Received suspend indication at count %d " , image_count ) ;
shared_data - > active = false ;
//closeEvent();
}
if ( config . max_suspend_time )
{
auto_resume_time = now . tv_sec + config . max_suspend_time ;
}
shared_data - > action & = ~ SUSPEND ;
}
if ( shared_data - > action & RESUME )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( Enabled ( ) & & ! Active ( ) )
{
Info ( " Received resume indication at count %d " , image_count ) ;
shared_data - > active = true ;
ref_image = * snap_image ;
ready_count = image_count + ( warmup_count / 2 ) ;
shared_data - > alarm_x = shared_data - > alarm_y = - 1 ;
}
shared_data - > action & = ~ RESUME ;
}
}
if ( auto_resume_time & & ( now . tv_sec > = auto_resume_time ) )
{
Info ( " Auto resuming at count %d " , image_count ) ;
shared_data - > active = true ;
ref_image = * snap_image ;
ready_count = image_count + ( warmup_count / 2 ) ;
auto_resume_time = 0 ;
}
static bool static_undef = true ;
static int last_section_mod = 0 ;
static bool last_signal ;
if ( static_undef )
{
2016-04-15 00:34:52 +08:00
// Sure would be nice to be able to assume that these were already initialized. It's just 1 compare/branch, but really not neccessary.
2016-04-04 22:11:48 +08:00
static_undef = false ;
timestamps = new struct timeval * [ pre_event_count ] ;
images = new Image * [ pre_event_count ] ;
last_signal = shared_data - > signal ;
}
if ( Enabled ( ) )
{
bool signal = shared_data - > signal ;
bool signal_change = ( signal ! = last_signal ) ;
2016-04-30 20:27:10 +08:00
//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 ( ) ) ;
2016-04-04 22:11:48 +08:00
if ( trigger_data - > trigger_state ! = TRIGGER_OFF )
{
unsigned int score = 0 ;
if ( Ready ( ) )
{
std : : string cause ;
Event : : StringSetMap noteSetMap ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( trigger_data - > trigger_state = = TRIGGER_ON )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
score + = trigger_data - > trigger_score ;
if ( ! event )
{
if ( cause . length ( ) )
cause + = " , " ;
cause + = trigger_data - > trigger_cause ;
}
Event : : StringSet noteSet ;
noteSet . insert ( trigger_data - > trigger_text ) ;
noteSetMap [ trigger_data - > trigger_cause ] = noteSet ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
if ( signal_change )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
const char * signalText ;
if ( ! signal )
signalText = " Lost " ;
else
{
signalText = " Reacquired " ;
score + = 100 ;
}
Warning ( " %s: %s " , SIGNAL_CAUSE , signalText ) ;
if ( event & & ! signal )
{
Info ( " %s: %03d - Closing event %d, signal loss " , name , image_count , event - > Id ( ) ) ;
closeEvent ( ) ;
last_section_mod = 0 ;
}
if ( ! event )
{
if ( cause . length ( ) )
cause + = " , " ;
cause + = SIGNAL_CAUSE ;
}
Event : : StringSet noteSet ;
noteSet . insert ( signalText ) ;
noteSetMap [ SIGNAL_CAUSE ] = noteSet ;
shared_data - > state = state = IDLE ;
shared_data - > active = signal ;
ref_image = * snap_image ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else if ( signal & & Active ( ) & & ( function = = MODECT | | function = = MOCORD ) )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Event : : StringSet zoneSet ;
int motion_score = last_motion_score ;
if ( ! ( image_count % ( motion_frame_skip + 1 ) ) )
{
// Get new score.
motion_score = last_motion_score = DetectMotion ( * snap_image , zoneSet ) ;
}
//int motion_score = DetectBlack( *snap_image, zoneSet );
if ( motion_score )
{
if ( ! event )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
score + = motion_score ;
if ( cause . length ( ) )
cause + = " , " ;
cause + = MOTION_CAUSE ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
{
score + = motion_score ;
}
noteSetMap [ MOTION_CAUSE ] = zoneSet ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
}
shared_data - > active = signal ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
if ( ( ! signal_change & & signal ) & & n_linked_monitors > 0 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
bool first_link = true ;
Event : : StringSet noteSet ;
for ( int i = 0 ; i < n_linked_monitors ; i + + )
{
if ( linked_monitors [ i ] - > isConnected ( ) )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( linked_monitors [ i ] - > hasAlarmed ( ) )
{
if ( ! event )
{
if ( first_link )
{
if ( cause . length ( ) )
cause + = " , " ;
cause + = LINKED_CAUSE ;
first_link = false ;
}
}
noteSet . insert ( linked_monitors [ i ] - > Name ( ) ) ;
score + = 50 ;
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
linked_monitors [ i ] - > connect ( ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
if ( noteSet . size ( ) > 0 )
noteSetMap [ LINKED_CAUSE ] = noteSet ;
2009-05-08 17:47:37 +08:00
}
2016-04-30 20:27:10 +08:00
//TODO: What happens is the event closes and sets recording to false then recording to true again so quickly that our capture daemon never picks it up. Maybe need a refresh flag?
2016-04-04 22:11:48 +08:00
if ( ( ! signal_change & & signal ) & & ( function = = RECORD | | function = = MOCORD ) )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( event )
{
2016-04-30 20:27:10 +08:00
//TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here??
snprintf ( video_store_data - > event_file , sizeof ( video_store_data - > event_file ) , " %s " , event - > getEventFile ( ) ) ;
2016-04-04 22:11:48 +08:00
int section_mod = timestamp - > tv_sec % section_length ;
if ( section_mod < last_section_mod )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( state = = IDLE | | state = = TAPE | | event_close_mode = = CLOSE_TIME )
{
if ( state = = TAPE )
{
shared_data - > state = state = IDLE ;
Info ( " %s: %03d - Closing event %d, section end " , name , image_count , event - > Id ( ) )
}
else
Info ( " %s: %03d - Closing event %d, section end forced " , name , image_count , event - > Id ( ) ) ;
closeEvent ( ) ;
last_section_mod = 0 ;
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
{
last_section_mod = section_mod ;
}
}
if ( ! event )
{
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
// Create event
2016-04-30 20:27:10 +08:00
event = new Event ( this , * timestamp , " Continuous " , noteSetMap , videoRecording ) ;
2016-04-04 22:11:48 +08:00
shared_data - > last_event = event - > Id ( ) ;
2016-04-30 20:27:10 +08:00
//set up video store data
snprintf ( video_store_data - > event_file , sizeof ( video_store_data - > event_file ) , " %s " , event - > getEventFile ( ) ) ;
video_store_data - > recording = true ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
Info ( " %s: %03d - Opening new event %d, section start " , name , image_count , event - > Id ( ) ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
/* To prevent cancelling out an existing alert\prealarm\alarm state */
if ( state = = IDLE )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
shared_data - > state = state = TAPE ;
}
2006-01-23 03:38:41 +08:00
2016-04-04 22:11:48 +08:00
//if ( config.overlap_timed_events )
if ( false )
{
int pre_index ;
int pre_event_images = pre_event_count ;
if ( analysis_fps )
{
// If analysis fps is set,
// compute the index for pre event images in the dedicated buffer
pre_index = image_count % pre_event_buffer_count ;
// Seek forward the next filled slot in to the buffer (oldest data)
// from the current position
while ( pre_event_images & & ! pre_event_buffer [ pre_index ] . timestamp - > tv_sec )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
pre_index = ( pre_index + 1 ) % pre_event_buffer_count ;
// Slot is empty, removing image from counter
pre_event_images - - ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
else
{
// If analysis fps is not set (analysis performed at capturing framerate),
// compute the index for pre event images in the capturing buffer
pre_index = ( ( index + image_buffer_count ) - pre_event_count ) % image_buffer_count ;
// Seek forward the next filled slot in to the buffer (oldest data)
// from the current position
while ( pre_event_images & & ! image_buffer [ pre_index ] . timestamp - > tv_sec )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
pre_index = ( pre_index + 1 ) % image_buffer_count ;
// Slot is empty, removing image from counter
pre_event_images - - ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
if ( pre_event_images )
{
if ( analysis_fps )
for ( int i = 0 ; i < pre_event_images ; i + + )
{
timestamps [ i ] = pre_event_buffer [ pre_index ] . timestamp ;
images [ i ] = pre_event_buffer [ pre_index ] . image ;
pre_index = ( pre_index + 1 ) % pre_event_buffer_count ;
}
else
for ( int i = 0 ; i < pre_event_images ; i + + )
{
timestamps [ i ] = image_buffer [ pre_index ] . timestamp ;
images [ i ] = image_buffer [ pre_index ] . image ;
pre_index = ( pre_index + 1 ) % image_buffer_count ;
}
event - > AddFrames ( pre_event_images , images , timestamps ) ;
}
}
}
}
if ( score )
{
if ( ( state = = IDLE | | state = = TAPE | | state = = PREALARM ) )
{
if ( Event : : PreAlarmCount ( ) > = ( alarm_frame_count - 1 ) )
{
Info ( " %s: %03d - Gone into alarm state " , name , image_count ) ;
shared_data - > state = state = ALARM ;
if ( signal_change | | ( function ! = MOCORD & & state ! = ALERT ) )
{
int pre_index ;
int pre_event_images = pre_event_count ;
if ( analysis_fps )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
// If analysis fps is set,
// compute the index for pre event images in the dedicated buffer
pre_index = image_count % pre_event_buffer_count ;
// Seek forward the next filled slot in to the buffer (oldest data)
// from the current position
while ( pre_event_images & & ! pre_event_buffer [ pre_index ] . timestamp - > tv_sec )
{
pre_index = ( pre_index + 1 ) % pre_event_buffer_count ;
// Slot is empty, removing image from counter
pre_event_images - - ;
}
event = new Event ( this , * ( pre_event_buffer [ pre_index ] . timestamp ) , cause , noteSetMap ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
// If analysis fps is not set (analysis performed at capturing framerate),
// compute the index for pre event images in the capturing buffer
if ( alarm_frame_count > 1 )
pre_index = ( ( index + image_buffer_count ) - ( ( alarm_frame_count - 1 ) + pre_event_count ) ) % image_buffer_count ;
else
pre_index = ( ( index + image_buffer_count ) - pre_event_count ) % image_buffer_count ;
// Seek forward the next filled slot in to the buffer (oldest data)
// from the current position
while ( pre_event_images & & ! image_buffer [ pre_index ] . timestamp - > tv_sec )
{
pre_index = ( pre_index + 1 ) % image_buffer_count ;
// Slot is empty, removing image from counter
pre_event_images - - ;
}
event = new Event ( this , * ( image_buffer [ pre_index ] . timestamp ) , cause , noteSetMap ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
shared_data - > last_event = event - > Id ( ) ;
2016-04-30 20:27:10 +08:00
//set up video store data
snprintf ( video_store_data - > event_file , sizeof ( video_store_data - > event_file ) , " %s " , event - > getEventFile ( ) ) ;
video_store_data - > recording = true ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
Info ( " %s: %03d - Opening new event %d, alarm start " , name , image_count , event - > Id ( ) ) ;
if ( pre_event_images )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( analysis_fps )
for ( int i = 0 ; i < pre_event_images ; i + + )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
timestamps [ i ] = pre_event_buffer [ pre_index ] . timestamp ;
images [ i ] = pre_event_buffer [ pre_index ] . image ;
pre_index = ( pre_index + 1 ) % pre_event_buffer_count ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
for ( int i = 0 ; i < pre_event_images ; i + + )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
timestamps [ i ] = image_buffer [ pre_index ] . timestamp ;
images [ i ] = image_buffer [ pre_index ] . image ;
pre_index = ( pre_index + 1 ) % image_buffer_count ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
event - > AddFrames ( pre_event_images , images , timestamps ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
if ( alarm_frame_count )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
event - > SavePreAlarmFrames ( ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
else if ( state ! = PREALARM )
{
Info ( " %s: %03d - Gone into prealarm state " , name , image_count ) ;
shared_data - > state = state = PREALARM ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
else if ( state = = ALERT )
{
Info ( " %s: %03d - Gone back into alarm state " , name , image_count ) ;
shared_data - > state = state = ALARM ;
}
last_alarm_count = image_count ;
2009-05-08 17:47:37 +08:00
}
2006-11-16 19:34:53 +08:00
else
{
2016-04-04 22:11:48 +08:00
if ( state = = ALARM )
{
Info ( " %s: %03d - Gone into alert state " , name , image_count ) ;
shared_data - > state = state = ALERT ;
}
else if ( state = = ALERT )
{
if ( image_count - last_alarm_count > post_event_count )
2006-11-16 19:34:53 +08:00
{
2016-04-04 22:11:48 +08:00
Info ( " %s: %03d - Left alarm state (%d) - %d(%d) images " , name , image_count , event - > Id ( ) , event - > Frames ( ) , event - > AlarmFrames ( ) ) ;
//if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE )
if ( function ! = MOCORD | | event_close_mode = = CLOSE_ALARM )
{
shared_data - > state = state = IDLE ;
Info ( " %s: %03d - Closing event %d, alarm end%s " , name , image_count , event - > Id ( ) , ( function = = MOCORD ) ? " , section truncated " : " " ) ;
2006-11-16 19:34:53 +08:00
closeEvent ( ) ;
2016-04-04 22:11:48 +08:00
}
else
{
shared_data - > state = state = TAPE ;
}
2006-11-16 19:34:53 +08:00
}
2016-04-04 22:11:48 +08:00
}
if ( state = = PREALARM )
{
if ( function ! = MOCORD )
{
shared_data - > state = state = IDLE ;
}
else
{
shared_data - > state = state = TAPE ;
}
}
if ( Event : : PreAlarmCount ( ) )
Event : : EmptyPreAlarmFrames ( ) ;
2006-11-16 19:34:53 +08:00
}
2016-04-04 22:11:48 +08:00
if ( state ! = IDLE )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( state = = PREALARM | | state = = ALARM )
{
if ( config . create_analysis_images )
{
bool got_anal_image = false ;
alarm_image . Assign ( * snap_image ) ;
for ( int i = 0 ; i < n_zones ; i + + )
{
if ( zones [ i ] - > Alarmed ( ) )
{
if ( zones [ i ] - > AlarmImage ( ) )
{
alarm_image . Overlay ( * ( zones [ i ] - > AlarmImage ( ) ) ) ;
got_anal_image = true ;
}
if ( config . record_event_stats & & state = = ALARM )
{
zones [ i ] - > RecordStats ( event ) ;
}
}
}
if ( got_anal_image )
{
if ( state = = PREALARM )
Event : : AddPreAlarmFrame ( snap_image , * timestamp , score , & alarm_image ) ;
else
event - > AddFrame ( snap_image , * timestamp , score , & alarm_image ) ;
}
else
{
if ( state = = PREALARM )
Event : : AddPreAlarmFrame ( snap_image , * timestamp , score ) ;
else
event - > AddFrame ( snap_image , * timestamp , score ) ;
}
}
else
{
for ( int i = 0 ; i < n_zones ; i + + )
{
if ( zones [ i ] - > Alarmed ( ) )
{
if ( config . record_event_stats & & state = = ALARM )
{
zones [ i ] - > RecordStats ( event ) ;
}
}
}
if ( state = = PREALARM )
Event : : AddPreAlarmFrame ( snap_image , * timestamp , score ) ;
else
event - > AddFrame ( snap_image , * timestamp , score ) ;
2013-11-04 15:11:33 +08:00
}
2016-04-04 22:11:48 +08:00
if ( event & & noteSetMap . size ( ) > 0 )
event - > updateNotes ( noteSetMap ) ;
}
else if ( state = = ALERT )
{
event - > AddFrame ( snap_image , * timestamp ) ;
if ( noteSetMap . size ( ) > 0 )
event - > updateNotes ( noteSetMap ) ;
}
else if ( state = = TAPE )
{
2016-04-30 20:27:10 +08:00
//Video Storage: activate only for supported cameras. Event::AddFrame knows whether or not we are recording video and saves frames accordingly
if ( ( GetOptVideoWriter ( ) = = 2 ) & & camera - > SupportsNativeVideo ( ) )
{
video_store_data - > recording = true ;
}
2016-04-04 22:11:48 +08:00
if ( ! ( image_count % ( frame_skip + 1 ) ) )
{
if ( config . bulk_frame_interval > 1 )
{
event - > AddFrame ( snap_image , * timestamp , ( event - > Frames ( ) < pre_event_count ? 0 : - 1 ) ) ;
}
else
{
event - > AddFrame ( snap_image , * timestamp ) ;
}
}
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
2015-07-27 22:24:32 +08:00
{
2016-04-04 22:11:48 +08:00
if ( event )
{
Info ( " %s: %03d - Closing event %d, trigger off " , name , image_count , event - > Id ( ) ) ;
closeEvent ( ) ;
}
shared_data - > state = state = IDLE ;
last_section_mod = 0 ;
}
if ( ( ! signal_change & & signal ) & & ( function = = MODECT | | function = = MOCORD ) )
{
if ( state = = ALARM ) {
ref_image . Blend ( * snap_image , alarm_ref_blend_perc ) ;
} else {
ref_image . Blend ( * snap_image , ref_blend_perc ) ;
}
}
last_signal = signal ;
}
shared_data - > last_read_index = index % image_buffer_count ;
//shared_data->last_read_time = image_buffer[index].timestamp->tv_sec;
shared_data - > last_read_time = now . tv_sec ;
if ( analysis_fps )
{
// If analysis fps is set, add analysed image to dedicated pre event buffer
int pre_index = image_count % pre_event_buffer_count ;
pre_event_buffer [ pre_index ] . image - > Assign ( * snap - > image ) ;
memcpy ( pre_event_buffer [ pre_index ] . timestamp , snap - > timestamp , sizeof ( struct timeval ) ) ;
}
image_count + + ;
return ( true ) ;
2016-04-06 05:14:46 +08:00
}
void Monitor : : Reload ( )
{
2016-04-04 22:11:48 +08:00
Debug ( 1 , " Reloading monitor %s " , name ) ;
if ( event )
Info ( " %s: %03d - Closing event %d, reloading " , name , image_count , event - > Id ( ) ) ;
closeEvent ( ) ;
static char sql [ ZM_SQL_MED_BUFSIZ ] ;
2016-04-30 20:27:10 +08:00
// This seems to have fallen out of date.
2016-04-04 22:11:48 +08:00
snprintf ( sql , sizeof ( sql ) , " select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d' " , id ) ;
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 ) ;
if ( n_monitors ! = 1 )
{
Error ( " Bogus number of monitors, %d, returned. Can't reload " , n_monitors ) ;
return ;
}
if ( MYSQL_ROW dbrow = mysql_fetch_row ( result ) )
{
int index = 0 ;
function = ( Function ) atoi ( dbrow [ index + + ] ) ;
enabled = atoi ( dbrow [ index + + ] ) ;
const char * p_linked_monitors = dbrow [ index + + ] ;
strncpy ( event_prefix , dbrow [ index + + ] , sizeof ( event_prefix ) ) ;
strncpy ( label_format , dbrow [ index + + ] , sizeof ( label_format ) ) ;
label_coord = Coord ( atoi ( dbrow [ index ] ) , atoi ( dbrow [ index + 1 ] ) ) ; index + = 2 ;
label_size = atoi ( dbrow [ index + + ] ) ;
warmup_count = atoi ( dbrow [ index + + ] ) ;
pre_event_count = atoi ( dbrow [ index + + ] ) ;
post_event_count = atoi ( dbrow [ index + + ] ) ;
alarm_frame_count = atoi ( dbrow [ index + + ] ) ;
section_length = atoi ( dbrow [ index + + ] ) ;
frame_skip = atoi ( dbrow [ index + + ] ) ;
motion_frame_skip = atoi ( dbrow [ index + + ] ) ;
analysis_fps = dbrow [ index ] ? strtod ( dbrow [ index ] , NULL ) : 0 ; index + + ;
analysis_update_delay = strtoul ( dbrow [ index + + ] , NULL , 0 ) ;
capture_delay = ( dbrow [ index ] & & atof ( dbrow [ index ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ index ] ) ) : 0 ; index + + ;
alarm_capture_delay = ( dbrow [ index ] & & atof ( dbrow [ index ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ index ] ) ) : 0 ; index + + ;
fps_report_interval = atoi ( dbrow [ index + + ] ) ;
ref_blend_perc = atoi ( dbrow [ index + + ] ) ;
alarm_ref_blend_perc = atoi ( dbrow [ index + + ] ) ;
track_motion = atoi ( dbrow [ index + + ] ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( dbrow [ index ] [ 0 ] = = ' # ' )
signal_check_colour = strtol ( dbrow [ index ] + 1 , 0 , 16 ) ;
else
signal_check_colour = strtol ( dbrow [ index ] , 0 , 16 ) ;
index + + ;
shared_data - > state = state = IDLE ;
shared_data - > alarm_x = shared_data - > alarm_y = - 1 ;
if ( enabled )
shared_data - > active = true ;
ready_count = image_count + warmup_count ;
ReloadLinkedMonitors ( p_linked_monitors ) ;
}
if ( mysql_errno ( & dbconn ) )
{
Error ( " Can't fetch row: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
mysql_free_result ( result ) ;
ReloadZones ( ) ;
2016-04-06 05:14:46 +08:00
}
2005-12-23 00:46:25 +08:00
2003-03-26 19:57:29 +08:00
void Monitor : : ReloadZones ( )
{
2016-04-04 22:11:48 +08:00
Debug ( 1 , " Reloading zones for monitor %s " , name ) ;
for ( int i = 0 ; i < n_zones ; i + + )
{
delete zones [ i ] ;
}
delete [ ] zones ;
zones = 0 ;
n_zones = Zone : : Load ( this , zones ) ;
//DumpZoneImage();
2003-03-26 19:57:29 +08:00
}
2006-01-23 02:31:55 +08:00
void Monitor : : ReloadLinkedMonitors ( const char * p_linked_monitors )
{
2016-04-04 22:11:48 +08:00
Debug ( 1 , " Reloading linked monitors for monitor %s, '%s' " , name , p_linked_monitors ) ;
if ( n_linked_monitors )
{
for ( int i = 0 ; i < n_linked_monitors ; i + + )
{
delete linked_monitors [ i ] ;
}
delete [ ] linked_monitors ;
linked_monitors = 0 ;
}
n_linked_monitors = 0 ;
if ( p_linked_monitors )
{
int n_link_ids = 0 ;
unsigned int link_ids [ 256 ] ;
char link_id_str [ 8 ] ;
char * dest_ptr = link_id_str ;
const char * src_ptr = p_linked_monitors ;
while ( 1 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
dest_ptr = link_id_str ;
while ( * src_ptr > = ' 0 ' & & * src_ptr < = ' 9 ' )
{
if ( ( dest_ptr - link_id_str ) < ( unsigned int ) ( sizeof ( link_id_str ) - 1 ) )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
* dest_ptr + + = * src_ptr + + ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
else
{
break ;
}
}
// Add the link monitor
if ( dest_ptr ! = link_id_str )
{
* dest_ptr = ' \0 ' ;
unsigned int link_id = atoi ( link_id_str ) ;
if ( link_id > 0 & & link_id ! = id )
{
Debug ( 3 , " Found linked monitor id %d " , link_id ) ;
int j ;
for ( j = 0 ; j < n_link_ids ; j + + )
{
if ( link_ids [ j ] = = link_id )
break ;
}
if ( j = = n_link_ids ) // Not already found
{
link_ids [ n_link_ids + + ] = link_id ;
}
}
}
if ( ! * src_ptr )
break ;
while ( * src_ptr & & ( * src_ptr < ' 0 ' | | * src_ptr > ' 9 ' ) )
src_ptr + + ;
if ( ! * src_ptr )
break ;
}
if ( n_link_ids > 0 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Debug ( 1 , " Linking to %d monitors " , n_link_ids ) ;
linked_monitors = new MonitorLink * [ n_link_ids ] ;
int count = 0 ;
for ( int i = 0 ; i < n_link_ids ; i + + )
{
Debug ( 1 , " Checking linked monitor %d " , link_ids [ i ] ) ;
static char sql [ ZM_SQL_SML_BUFSIZ ] ;
snprintf ( sql , sizeof ( sql ) , " select Id, Name from Monitors where Id = %d and Function != 'None' and Function != 'Monitor' and Enabled = 1 " , link_ids [ i ] ) ;
if ( mysql_query ( & dbconn , sql ) )
{
Error ( " Can't run query: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
MYSQL_RES * result = mysql_store_result ( & dbconn ) ;
if ( ! result )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Error ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
int n_monitors = mysql_num_rows ( result ) ;
if ( n_monitors = = 1 )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
MYSQL_ROW dbrow = mysql_fetch_row ( result ) ;
Debug ( 1 , " Linking to monitor %d " , link_ids [ i ] ) ;
linked_monitors [ count + + ] = new MonitorLink ( link_ids [ i ] , dbrow [ 1 ] ) ;
}
else
{
Warning ( " Can't link to monitor %d, invalid id, function or not enabled " , link_ids [ i ] ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
mysql_free_result ( result ) ;
}
n_linked_monitors = count ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
2006-01-23 02:31:55 +08:00
}
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L
2005-10-18 05:55:02 +08:00
int Monitor : : LoadLocalMonitors ( const char * device , Monitor * * & monitors , Purpose purpose )
2003-03-26 19:57:29 +08:00
{
2016-04-30 20:27:10 +08:00
std : : string sql = " select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, 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 Function != 'None' and Type = 'Local' " ;
2016-04-04 22:11:48 +08:00
if ( device [ 0 ] ) {
sql + = " AND Device=' " ;
sql + = device ;
sql + = " ' " ;
}
if ( staticConfig . SERVER_ID ) {
sql + = stringtf ( " AND ServerId=%d " , staticConfig . SERVER_ID ) ;
}
Debug ( 1 , " Loading Local Monitors with %s " , sql . c_str ( ) ) ;
MYSQL_RES * result = zmDbFetch ( sql . c_str ( ) ) ;
if ( ! result ) {
Error ( " Can't load local monitors: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
int n_monitors = mysql_num_rows ( result ) ;
Debug ( 1 , " Got %d monitors " , n_monitors ) ;
delete [ ] monitors ;
monitors = new Monitor * [ n_monitors ] ;
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + )
{
int col = 0 ;
int id = atoi ( dbrow [ col ] ) ; col + + ;
const char * name = dbrow [ col ] ; col + + ;
unsigned int server_id = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int function = atoi ( dbrow [ col ] ) ; col + + ;
int enabled = atoi ( dbrow [ col ] ) ; col + + ;
const char * linked_monitors = dbrow [ col ] ; col + + ;
const char * device = dbrow [ col ] ; col + + ;
int channel = atoi ( dbrow [ col ] ) ; col + + ;
int format = atoi ( dbrow [ col ] ) ; col + + ;
bool v4l_multi_buffer = config . v4l_multi_buffer ;
if ( dbrow [ col ] ) {
if ( * dbrow [ col ] = = ' 0 ' ) {
v4l_multi_buffer = false ;
} else if ( * dbrow [ col ] = = ' 1 ' ) {
v4l_multi_buffer = true ;
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
col + + ;
int v4l_captures_per_frame = 0 ;
if ( dbrow [ col ] ) {
v4l_captures_per_frame = atoi ( dbrow [ col ] ) ;
} else {
v4l_captures_per_frame = config . captures_per_frame ;
}
2014-09-09 03:20:35 +08:00
Debug ( 1 , " Got %d for v4l_captures_per_frame " , v4l_captures_per_frame ) ;
2016-04-04 22:11:48 +08:00
col + + ;
const char * method = dbrow [ col ] ; col + + ;
int width = atoi ( dbrow [ col ] ) ; col + + ;
int height = atoi ( dbrow [ col ] ) ; col + + ;
int colours = atoi ( dbrow [ col ] ) ; col + + ;
int palette = atoi ( dbrow [ col ] ) ; col + + ;
Orientation orientation = ( Orientation ) atoi ( dbrow [ col ] ) ; col + + ;
unsigned int deinterlacing = atoi ( dbrow [ col ] ) ; col + + ;
2016-04-30 20:27:10 +08:00
int savejpegs = atoi ( dbrow [ col ] ) ; col + + ;
int videowriter = atoi ( dbrow [ col ] ) ; col + + ;
std : : string encoderparams = dbrow [ col ] ; col + + ;
bool record_audio = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2016-04-04 22:11:48 +08:00
int brightness = atoi ( dbrow [ col ] ) ; col + + ;
int contrast = atoi ( dbrow [ col ] ) ; col + + ;
int hue = atoi ( dbrow [ col ] ) ; col + + ;
int colour = atoi ( dbrow [ col ] ) ; col + + ;
const char * event_prefix = dbrow [ col ] ; col + + ;
const char * label_format = dbrow [ col ] ; col + + ;
int label_x = atoi ( dbrow [ col ] ) ; col + + ;
int label_y = atoi ( dbrow [ col ] ) ; col + + ;
int label_size = atoi ( dbrow [ col ] ) ; col + + ;
int image_buffer_count = atoi ( dbrow [ col ] ) ; col + + ;
int warmup_count = atoi ( dbrow [ col ] ) ; col + + ;
int pre_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int post_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int stream_replay_buffer = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_frame_count = atoi ( dbrow [ col ] ) ; col + + ;
int section_length = atoi ( dbrow [ col ] ) ; col + + ;
int frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
int motion_frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
double analysis_fps = dbrow [ col ] ? strtod ( dbrow [ col ] , NULL ) : 0 ; col + + ;
unsigned int analysis_update_delay = strtoul ( dbrow [ col + + ] , NULL , 0 ) ;
int capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int alarm_capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int fps_report_interval = atoi ( dbrow [ col ] ) ; col + + ;
int ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int track_motion = atoi ( dbrow [ col ] ) ; col + + ;
int signal_check_colour ;
if ( dbrow [ col ] [ 0 ] = = ' # ' )
signal_check_colour = strtol ( dbrow [ col ] + 1 , 0 , 16 ) ;
else
signal_check_colour = strtol ( dbrow [ col ] , 0 , 16 ) ;
col + + ;
bool embed_exif = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
int extras = ( deinterlacing > > 24 ) & 0xff ;
Camera * camera = new LocalCamera (
id ,
device ,
channel ,
format ,
v4l_multi_buffer ,
v4l_captures_per_frame ,
method ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
palette ,
brightness ,
contrast ,
hue ,
colour ,
purpose = = CAPTURE ,
2016-04-30 20:27:10 +08:00
record_audio ,
2016-04-04 22:11:48 +08:00
extras
) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
monitors [ i ] = new Monitor (
id ,
name ,
server_id ,
function ,
enabled ,
linked_monitors ,
camera ,
orientation ,
deinterlacing ,
2016-04-30 20:27:10 +08:00
savejpegs ,
videowriter ,
encoderparams ,
record_audio ,
2016-04-04 22:11:48 +08:00
event_prefix ,
label_format ,
Coord ( label_x , label_y ) ,
label_size ,
image_buffer_count ,
warmup_count ,
pre_event_count ,
post_event_count ,
stream_replay_buffer ,
alarm_frame_count ,
section_length ,
frame_skip ,
motion_frame_skip ,
analysis_fps ,
analysis_update_delay ,
capture_delay ,
alarm_capture_delay ,
fps_report_interval ,
ref_blend_perc ,
alarm_ref_blend_perc ,
track_motion ,
signal_check_colour ,
embed_exif ,
purpose ,
0 ,
0
) ;
Zone * * zones = 0 ;
int n_zones = Zone : : Load ( monitors [ i ] , zones ) ;
monitors [ i ] - > AddZones ( n_zones , zones ) ;
monitors [ i ] - > AddPrivacyBitmask ( zones ) ;
Debug ( 1 , " Loaded monitor %d(%s), %d zones " , id , name , n_zones ) ;
}
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-03-26 19:57:29 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L
2003-03-26 19:57:29 +08:00
2009-05-08 17:47:37 +08:00
int Monitor : : LoadRemoteMonitors ( const char * protocol , const char * host , const char * port , const char * path , Monitor * * & monitors , Purpose purpose )
{
2016-04-30 20:27:10 +08:00
std : : string sql = " select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, 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, Exif from Monitors where Function != 'None' and Type = 'Remote' " ;
2016-04-04 22:11:48 +08:00
if ( staticConfig . SERVER_ID ) {
sql + = stringtf ( " AND ServerId=%d " , staticConfig . SERVER_ID ) ;
}
if ( protocol ) {
sql + = stringtf ( " AND Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s' " , protocol , host , port , path ) ;
}
Debug ( 1 , " Loading Remote Monitors with %s " , sql . c_str ( ) ) ;
MYSQL_RES * result = zmDbFetch ( sql . c_str ( ) ) ;
if ( ! result ) {
Error ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
int n_monitors = mysql_num_rows ( result ) ;
Debug ( 1 , " Got %d monitors " , n_monitors ) ;
delete [ ] monitors ;
monitors = new Monitor * [ n_monitors ] ;
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + )
{
int col = 0 ;
int id = atoi ( dbrow [ col ] ) ; col + + ;
std : : string name = dbrow [ col ] ; col + + ;
unsigned int server_id = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int function = atoi ( dbrow [ col ] ) ; col + + ;
int enabled = atoi ( dbrow [ col ] ) ; col + + ;
const char * linked_monitors = dbrow [ col ] ; col + + ;
2015-07-21 04:28:21 +08:00
2016-04-04 22:11:48 +08:00
std : : string protocol = dbrow [ col ] ; col + + ;
std : : string method = dbrow [ col ] ; col + + ;
std : : string host = dbrow [ col ] ; col + + ;
std : : string port = dbrow [ col ] ; col + + ;
std : : string path = dbrow [ col ] ; col + + ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
int width = atoi ( dbrow [ col ] ) ; col + + ;
int height = atoi ( dbrow [ col ] ) ; col + + ;
int colours = atoi ( dbrow [ col ] ) ; col + + ;
/* int palette = atoi(dbrow[col]); */ col + + ;
Orientation orientation = ( Orientation ) atoi ( dbrow [ col ] ) ; col + + ;
unsigned int deinterlacing = atoi ( dbrow [ col ] ) ; col + + ;
bool rtsp_describe = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2016-04-30 20:27:10 +08:00
int savejpegs = atoi ( dbrow [ col ] ) ; col + + ;
int videowriter = atoi ( dbrow [ col ] ) ; col + + ;
std : : string encoderparams = dbrow [ col ] ; col + + ;
bool record_audio = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2016-04-04 22:11:48 +08:00
int brightness = atoi ( dbrow [ col ] ) ; col + + ;
int contrast = atoi ( dbrow [ col ] ) ; col + + ;
int hue = atoi ( dbrow [ col ] ) ; col + + ;
int colour = atoi ( dbrow [ col ] ) ; col + + ;
2005-10-18 05:55:02 +08:00
2016-04-04 22:11:48 +08:00
std : : string event_prefix = dbrow [ col ] ; col + + ;
std : : string label_format = dbrow [ col ] ; col + + ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
int label_x = atoi ( dbrow [ col ] ) ; col + + ;
int label_y = atoi ( dbrow [ col ] ) ; col + + ;
int label_size = atoi ( dbrow [ col ] ) ; col + + ;
2003-03-26 19:57:29 +08:00
2016-04-04 22:11:48 +08:00
int image_buffer_count = atoi ( dbrow [ col ] ) ; col + + ;
int warmup_count = atoi ( dbrow [ col ] ) ; col + + ;
int pre_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int post_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int stream_replay_buffer = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_frame_count = atoi ( dbrow [ col ] ) ; col + + ;
int section_length = atoi ( dbrow [ col ] ) ; col + + ;
int frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
int motion_frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
double analysis_fps = dbrow [ col ] ? strtod ( dbrow [ col ] , NULL ) : 0 ; col + + ;
unsigned int analysis_update_delay = strtoul ( dbrow [ col + + ] , NULL , 0 ) ;
int capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int alarm_capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int fps_report_interval = atoi ( dbrow [ col ] ) ; col + + ;
int ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int track_motion = atoi ( dbrow [ col ] ) ; col + + ;
bool embed_exif = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
Camera * camera = 0 ;
if ( protocol = = " http " )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
camera = new RemoteCameraHttp (
id ,
method ,
host , // Host
port , // Port
path , // Path
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
}
2008-10-17 00:11:49 +08:00
# if HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
else if ( protocol = = " rtsp " )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
camera = new RemoteCameraRtsp (
id ,
method ,
host , // Host
port , // Port
path , // Path
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
rtsp_describe ,
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
2009-05-08 17:47:37 +08:00
}
2008-10-17 00:11:49 +08:00
# endif // HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
else
{
Fatal ( " Unexpected remote camera protocol '%s' " , protocol . c_str ( ) ) ;
}
monitors [ i ] = new Monitor (
id ,
name . c_str ( ) ,
server_id ,
function ,
enabled ,
linked_monitors ,
camera ,
orientation ,
deinterlacing ,
2016-04-30 20:27:10 +08:00
savejpegs ,
videowriter ,
encoderparams ,
record_audio ,
2016-04-04 22:11:48 +08:00
event_prefix . c_str ( ) ,
label_format . c_str ( ) ,
Coord ( label_x , label_y ) ,
label_size ,
image_buffer_count ,
warmup_count ,
pre_event_count ,
post_event_count ,
stream_replay_buffer ,
alarm_frame_count ,
section_length ,
frame_skip ,
motion_frame_skip ,
analysis_fps ,
analysis_update_delay ,
capture_delay ,
alarm_capture_delay ,
fps_report_interval ,
ref_blend_perc ,
alarm_ref_blend_perc ,
track_motion ,
RGB_WHITE ,
embed_exif ,
purpose ,
0 ,
0
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
) ;
Zone * * zones = 0 ;
int n_zones = Zone : : Load ( monitors [ i ] , zones ) ;
monitors [ i ] - > AddZones ( n_zones , zones ) ;
monitors [ i ] - > AddPrivacyBitmask ( zones ) ;
Debug ( 1 , " Loaded monitor %d(%s), %d zones " , id , name . c_str ( ) , n_zones ) ;
}
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-03-26 19:57:29 +08:00
}
2016-04-04 22:11:48 +08:00
int Monitor : : LoadFileMonitors ( const char * file , Monitor * * & monitors , Purpose purpose )
2003-03-26 19:57:29 +08:00
{
2016-04-30 20:27:10 +08:00
std : : string sql = " select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, 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, Exif from Monitors where Function != 'None' and Type = 'File' " ;
2016-04-04 22:11:48 +08:00
if ( file [ 0 ] ) {
sql + = " AND Path=' " ;
sql + = file ;
sql + = " ' " ;
}
if ( staticConfig . SERVER_ID ) {
sql + = stringtf ( " AND ServerId=%d " , staticConfig . SERVER_ID ) ;
}
Debug ( 1 , " Loading File Monitors with %s " , sql . c_str ( ) ) ;
MYSQL_RES * result = zmDbFetch ( sql . c_str ( ) ) ;
if ( ! result )
{
Error ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
int n_monitors = mysql_num_rows ( result ) ;
Debug ( 1 , " Got %d monitors " , n_monitors ) ;
delete [ ] monitors ;
monitors = new Monitor * [ n_monitors ] ;
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + )
{
int col = 0 ;
int id = atoi ( dbrow [ col ] ) ; col + + ;
const char * name = dbrow [ col ] ; col + + ;
2015-08-27 23:16:58 +08:00
unsigned int server_id = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
2015-08-27 23:14:00 +08:00
int function = atoi ( dbrow [ col ] ) ; col + + ;
int enabled = atoi ( dbrow [ col ] ) ; col + + ;
2016-04-04 22:11:48 +08:00
const char * linked_monitors = dbrow [ col ] ; col + + ;
2015-08-27 23:14:00 +08:00
2016-04-04 22:11:48 +08:00
const char * path = dbrow [ col ] ; col + + ;
2015-08-27 23:14:00 +08:00
2016-04-04 22:11:48 +08:00
int width = atoi ( dbrow [ col ] ) ; col + + ;
int height = atoi ( dbrow [ col ] ) ; col + + ;
int colours = atoi ( dbrow [ col ] ) ; col + + ;
/* int palette = atoi(dbrow[col]); */ col + + ;
Orientation orientation = ( Orientation ) atoi ( dbrow [ col ] ) ; col + + ;
unsigned int deinterlacing = atoi ( dbrow [ col ] ) ; col + + ;
2016-04-30 20:27:10 +08:00
int savejpegs = atoi ( dbrow [ col ] ) ; col + + ;
int videowriter = atoi ( dbrow [ col ] ) ; col + + ;
std : : string encoderparams = dbrow [ col ] ; col + + ;
bool record_audio = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2016-04-04 22:11:48 +08:00
int brightness = atoi ( dbrow [ col ] ) ; col + + ;
int contrast = atoi ( dbrow [ col ] ) ; col + + ;
int hue = atoi ( dbrow [ col ] ) ; col + + ;
int colour = atoi ( dbrow [ col ] ) ; col + + ;
2014-09-09 04:56:40 +08:00
2016-04-04 22:11:48 +08:00
const char * event_prefix = dbrow [ col ] ; col + + ;
const char * label_format = dbrow [ col ] ; col + + ;
2015-08-27 23:14:00 +08:00
2016-04-04 22:11:48 +08:00
int label_x = atoi ( dbrow [ col ] ) ; col + + ;
int label_y = atoi ( dbrow [ col ] ) ; col + + ;
int label_size = atoi ( dbrow [ col ] ) ; col + + ;
int image_buffer_count = atoi ( dbrow [ col ] ) ; col + + ;
int warmup_count = atoi ( dbrow [ col ] ) ; col + + ;
int pre_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int post_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int stream_replay_buffer = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_frame_count = atoi ( dbrow [ col ] ) ; col + + ;
int section_length = atoi ( dbrow [ col ] ) ; col + + ;
int frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
int motion_frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
double analysis_fps = dbrow [ col ] ? strtod ( dbrow [ col ] , NULL ) : 0 ; col + + ;
unsigned int analysis_update_delay = strtoul ( dbrow [ col + + ] , NULL , 0 ) ;
int capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int alarm_capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int fps_report_interval = atoi ( dbrow [ col ] ) ; col + + ;
int ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int track_motion = atoi ( dbrow [ col ] ) ; col + + ;
bool embed_exif = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
Camera * camera = new FileCamera (
id ,
path , // File
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
monitors [ i ] = new Monitor (
id ,
name ,
server_id ,
function ,
enabled ,
linked_monitors ,
camera ,
orientation ,
deinterlacing ,
2016-04-30 20:27:10 +08:00
savejpegs ,
videowriter ,
encoderparams ,
record_audio ,
2016-04-04 22:11:48 +08:00
event_prefix ,
label_format ,
Coord ( label_x , label_y ) ,
label_size ,
image_buffer_count ,
warmup_count ,
pre_event_count ,
post_event_count ,
stream_replay_buffer ,
alarm_frame_count ,
section_length ,
frame_skip ,
motion_frame_skip ,
analysis_fps ,
analysis_update_delay ,
capture_delay ,
alarm_capture_delay ,
fps_report_interval ,
ref_blend_perc ,
alarm_ref_blend_perc ,
track_motion ,
embed_exif ,
RGB_WHITE ,
purpose ,
0 ,
0
) ;
Zone * * zones = 0 ;
int n_zones = Zone : : Load ( monitors [ i ] , zones ) ;
monitors [ i ] - > AddZones ( n_zones , zones ) ;
monitors [ i ] - > AddPrivacyBitmask ( zones ) ;
Debug ( 1 , " Loaded monitor %d(%s), %d zones " , id , name , n_zones ) ;
}
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 ) ;
2005-10-18 05:55:02 +08:00
}
2009-01-28 23:02:33 +08:00
# if HAVE_LIBAVFORMAT
2009-01-20 23:01:32 +08:00
int Monitor : : LoadFfmpegMonitors ( const char * file , Monitor * * & monitors , Purpose purpose )
{
2016-04-30 20:27:10 +08:00
std : : string sql = " select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, 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, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg' " ;
2016-04-04 22:11:48 +08:00
if ( file [ 0 ] ) {
sql + = " AND Path = ' " ;
sql + = file ;
sql + = " ' " ;
}
if ( staticConfig . SERVER_ID ) {
sql + = stringtf ( " AND ServerId=%d " , staticConfig . SERVER_ID ) ;
}
Debug ( 1 , " Loading FFMPEG Monitors with %s " , sql . c_str ( ) ) ;
MYSQL_RES * result = zmDbFetch ( sql . c_str ( ) ) ;
if ( ! result ) {
Error ( " Cannot load FfmpegMonitors " ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
int n_monitors = mysql_num_rows ( result ) ;
Debug ( 1 , " Got %d monitors " , n_monitors ) ;
delete [ ] monitors ;
monitors = new Monitor * [ n_monitors ] ;
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + )
{
int col = 0 ;
int id = atoi ( dbrow [ col ] ) ; col + + ;
const char * name = dbrow [ col ] ; col + + ;
unsigned int server_id = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int function = atoi ( dbrow [ col ] ) ; col + + ;
int enabled = atoi ( dbrow [ col ] ) ; col + + ;
const char * linked_monitors = dbrow [ col ] ; col + + ;
const char * path = dbrow [ col ] ; col + + ;
const char * method = dbrow [ col ] ; col + + ;
const char * options = dbrow [ col ] ; col + + ;
2015-08-27 23:14:00 +08:00
int width = atoi ( dbrow [ col ] ) ; col + + ;
int height = atoi ( dbrow [ col ] ) ; col + + ;
int colours = atoi ( dbrow [ col ] ) ; col + + ;
2016-04-04 22:11:48 +08:00
/* int palette = atoi(dbrow[col]); */ col + + ;
2015-08-27 23:14:00 +08:00
Orientation orientation = ( Orientation ) atoi ( dbrow [ col ] ) ; col + + ;
unsigned int deinterlacing = atoi ( dbrow [ col ] ) ; col + + ;
2016-04-30 20:27:10 +08:00
int savejpegs = atoi ( dbrow [ col ] ) ; col + + ;
int videowriter = atoi ( dbrow [ col ] ) ; col + + ;
std : : string encoderparams = dbrow [ col ] ; col + + ;
bool record_audio = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2015-08-27 23:14:00 +08:00
int brightness = atoi ( dbrow [ col ] ) ; col + + ;
int contrast = atoi ( dbrow [ col ] ) ; col + + ;
int hue = atoi ( dbrow [ col ] ) ; col + + ;
int colour = atoi ( dbrow [ col ] ) ; col + + ;
2016-04-04 22:11:48 +08:00
const char * event_prefix = dbrow [ col ] ; col + + ;
const char * label_format = dbrow [ col ] ; col + + ;
2015-08-27 23:14:00 +08:00
int label_x = atoi ( dbrow [ col ] ) ; col + + ;
int label_y = atoi ( dbrow [ col ] ) ; col + + ;
int label_size = atoi ( dbrow [ col ] ) ; col + + ;
int image_buffer_count = atoi ( dbrow [ col ] ) ; col + + ;
int warmup_count = atoi ( dbrow [ col ] ) ; col + + ;
int pre_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int post_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int stream_replay_buffer = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_frame_count = atoi ( dbrow [ col ] ) ; col + + ;
int section_length = atoi ( dbrow [ col ] ) ; col + + ;
int frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
int motion_frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
double analysis_fps = dbrow [ col ] ? strtod ( dbrow [ col ] , NULL ) : 0 ; col + + ;
unsigned int analysis_update_delay = strtoul ( dbrow [ col + + ] , NULL , 0 ) ;
int capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int alarm_capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int fps_report_interval = atoi ( dbrow [ col ] ) ; col + + ;
int ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int track_motion = atoi ( dbrow [ col ] ) ; col + + ;
2015-08-20 01:30:48 +08:00
bool embed_exif = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2013-03-17 07:45:21 +08:00
2016-04-04 22:11:48 +08:00
Camera * camera = new FfmpegCamera (
id ,
path , // File
method ,
options ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
2012-01-30 14:00:22 +08:00
2016-04-04 22:11:48 +08:00
monitors [ i ] = new Monitor (
id ,
name ,
server_id ,
function ,
enabled ,
linked_monitors ,
camera ,
orientation ,
deinterlacing ,
2016-04-30 20:27:10 +08:00
savejpegs ,
videowriter ,
encoderparams ,
record_audio ,
2016-04-04 22:11:48 +08:00
event_prefix ,
label_format ,
Coord ( label_x , label_y ) ,
label_size ,
image_buffer_count ,
warmup_count ,
pre_event_count ,
post_event_count ,
stream_replay_buffer ,
alarm_frame_count ,
section_length ,
frame_skip ,
motion_frame_skip ,
analysis_fps ,
analysis_update_delay ,
capture_delay ,
alarm_capture_delay ,
fps_report_interval ,
ref_blend_perc ,
alarm_ref_blend_perc ,
track_motion ,
embed_exif ,
RGB_WHITE ,
purpose ,
0 ,
0
) ;
Zone * * zones = 0 ;
int n_zones = Zone : : Load ( monitors [ i ] , zones ) ;
monitors [ i ] - > AddZones ( n_zones , zones ) ;
monitors [ i ] - > AddPrivacyBitmask ( zones ) ;
Debug ( 1 , " Loaded monitor %d(%s), %d zones " , id , name , n_zones ) ;
}
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 ) ;
2009-01-20 23:01:32 +08:00
}
2009-01-28 23:02:33 +08:00
# endif // HAVE_LIBAVFORMAT
2009-01-20 23:01:32 +08:00
2016-04-04 22:11:48 +08:00
Monitor * Monitor : : Load ( unsigned int p_id , bool load_zones , Purpose purpose )
{
2016-04-30 20:27:10 +08:00
std : : string sql = stringtf ( " select Id, Name, ServerId, 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 ) ;
2016-04-04 22:11:48 +08:00
MYSQL_ROW dbrow = zmDbFetchOne ( sql . c_str ( ) ) ;
if ( ! dbrow ) {
Error ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ;
exit ( mysql_errno ( & dbconn ) ) ;
}
Monitor * monitor = 0 ;
unsigned int col = 0 ;
unsigned int id = atoi ( dbrow [ col ] ) ; col + + ;
std : : string name = dbrow [ col ] ; col + + ;
unsigned int server_id = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
std : : string type = dbrow [ col ] ; col + + ;
int function = atoi ( dbrow [ col ] ) ; col + + ;
int enabled = atoi ( dbrow [ col ] ) ; col + + ;
std : : string linked_monitors = dbrow [ col ] ; col + + ;
std : : string device = dbrow [ col ] ; col + + ;
int channel = atoi ( dbrow [ col ] ) ; col + + ;
int format = atoi ( dbrow [ col ] ) ; col + + ;
bool v4l_multi_buffer = config . v4l_multi_buffer ;
if ( dbrow [ col ] ) {
if ( * dbrow [ col ] = = ' 0 ' ) {
v4l_multi_buffer = false ;
} else if ( * dbrow [ col ] = = ' 1 ' ) {
v4l_multi_buffer = true ;
}
}
col + + ;
int v4l_captures_per_frame = 0 ;
if ( dbrow [ col ] ) {
v4l_captures_per_frame = atoi ( dbrow [ col ] ) ;
} else {
v4l_captures_per_frame = config . captures_per_frame ;
}
Debug ( 1 , " Got %d for v4l_captures_per_frame " , v4l_captures_per_frame ) ;
col + + ;
std : : string protocol = dbrow [ col ] ; col + + ;
std : : string method = dbrow [ col ] ; col + + ;
std : : string host = dbrow [ col ] ; col + + ;
std : : string port = dbrow [ col ] ; col + + ;
std : : string path = dbrow [ col ] ; col + + ;
std : : string options = dbrow [ col ] ; col + + ;
std : : string user = dbrow [ col ] ; col + + ;
std : : string pass = dbrow [ col ] ; col + + ;
int width = atoi ( dbrow [ col ] ) ; col + + ;
int height = atoi ( dbrow [ col ] ) ; col + + ;
int colours = atoi ( dbrow [ col ] ) ; col + + ;
int palette = atoi ( dbrow [ col ] ) ; col + + ;
Orientation orientation = ( Orientation ) atoi ( dbrow [ col ] ) ; col + + ;
unsigned int deinterlacing = atoi ( dbrow [ col ] ) ; col + + ;
bool rtsp_describe = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2016-04-30 20:27:10 +08:00
int savejpegs = atoi ( dbrow [ col ] ) ; col + + ;
int videowriter = atoi ( dbrow [ col ] ) ; col + + ;
std : : string encoderparams = dbrow [ col ] ; col + + ;
bool record_audio = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
2016-04-04 22:11:48 +08:00
int brightness = atoi ( dbrow [ col ] ) ; col + + ;
int contrast = atoi ( dbrow [ col ] ) ; col + + ;
int hue = atoi ( dbrow [ col ] ) ; col + + ;
int colour = atoi ( dbrow [ col ] ) ; col + + ;
std : : string event_prefix = dbrow [ col ] ; col + + ;
std : : string label_format = dbrow [ col ] ; col + + ;
int label_x = atoi ( dbrow [ col ] ) ; col + + ;
int label_y = atoi ( dbrow [ col ] ) ; col + + ;
int label_size = atoi ( dbrow [ col ] ) ; col + + ;
int image_buffer_count = atoi ( dbrow [ col ] ) ; col + + ;
int warmup_count = atoi ( dbrow [ col ] ) ; col + + ;
int pre_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int post_event_count = atoi ( dbrow [ col ] ) ; col + + ;
int stream_replay_buffer = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_frame_count = atoi ( dbrow [ col ] ) ; col + + ;
int section_length = atoi ( dbrow [ col ] ) ; col + + ;
int frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
int motion_frame_skip = atoi ( dbrow [ col ] ) ; col + + ;
double analysis_fps = dbrow [ col ] ? strtod ( dbrow [ col ] , NULL ) : 0 ; col + + ;
unsigned int analysis_update_delay = strtoul ( dbrow [ col + + ] , NULL , 0 ) ;
int capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int alarm_capture_delay = ( dbrow [ col ] & & atof ( dbrow [ col ] ) > 0.0 ) ? int ( DT_PREC_3 / atof ( dbrow [ col ] ) ) : 0 ; col + + ;
int fps_report_interval = atoi ( dbrow [ col ] ) ; col + + ;
int ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int alarm_ref_blend_perc = atoi ( dbrow [ col ] ) ; col + + ;
int track_motion = atoi ( dbrow [ col ] ) ; col + + ;
int signal_check_colour ;
if ( dbrow [ col ] [ 0 ] = = ' # ' )
signal_check_colour = strtol ( dbrow [ col ] + 1 , 0 , 16 ) ;
else
signal_check_colour = strtol ( dbrow [ col ] , 0 , 16 ) ;
col + + ;
bool embed_exif = ( * dbrow [ col ] ! = ' 0 ' ) ; col + + ;
int extras = ( deinterlacing > > 24 ) & 0xff ;
Camera * camera = 0 ;
if ( type = = " Local " )
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L
2016-04-04 22:11:48 +08:00
camera = new LocalCamera (
id ,
device . c_str ( ) ,
channel ,
format ,
v4l_multi_buffer ,
v4l_captures_per_frame ,
method ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
palette ,
brightness ,
contrast ,
hue ,
colour ,
purpose = = CAPTURE ,
2016-04-30 20:27:10 +08:00
record_audio ,
2016-04-04 22:11:48 +08:00
extras
) ;
2011-02-16 05:59:06 +08:00
# else // ZM_HAS_V4L
2016-04-04 22:11:48 +08:00
Fatal ( " You must have video4linux libraries and headers installed to use local analog or USB cameras for monitor %d " , id ) ;
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L
2016-04-04 22:11:48 +08:00
}
else if ( type = = " Remote " )
{
if ( protocol = = " http " )
{
camera = new RemoteCameraHttp (
id ,
method . c_str ( ) ,
host . c_str ( ) ,
port . c_str ( ) ,
path . c_str ( ) ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
}
else if ( protocol = = " rtsp " )
2015-08-27 23:14:00 +08:00
{
2011-02-16 05:59:06 +08:00
# if HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
camera = new RemoteCameraRtsp (
id ,
method . c_str ( ) ,
host . c_str ( ) ,
port . c_str ( ) ,
path . c_str ( ) ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
rtsp_describe ,
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
2011-02-16 05:59:06 +08:00
# else // HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
Fatal ( " You must have ffmpeg libraries installed to use remote camera protocol '%s' for monitor %d " , protocol . c_str ( ) , id ) ;
2009-01-28 23:02:33 +08:00
# endif // HAVE_LIBAVFORMAT
2015-08-27 23:14:00 +08:00
}
2016-04-04 22:11:48 +08:00
else
2015-08-27 23:14:00 +08:00
{
2016-04-04 22:11:48 +08:00
Fatal ( " Unexpected remote camera protocol '%s' for monitor %d " , protocol . c_str ( ) , id ) ;
}
}
else if ( type = = " File " )
{
camera = new FileCamera (
id ,
path . c_str ( ) ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
}
else if ( type = = " Ffmpeg " )
{
2011-02-16 05:59:06 +08:00
# if HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
camera = new FfmpegCamera (
id ,
path . c_str ( ) ,
method ,
options ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
2011-02-16 05:59:06 +08:00
# else // HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
Fatal ( " You must have ffmpeg libraries installed to use ffmpeg cameras for monitor %d " , id ) ;
2009-01-28 23:02:33 +08:00
# endif // HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
}
else if ( type = = " Libvlc " )
{
2013-12-13 01:45:29 +08:00
# if HAVE_LIBVLC
2016-04-04 22:11:48 +08:00
camera = new LibvlcCamera (
id ,
path . c_str ( ) ,
method ,
options ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
2013-12-13 01:45:29 +08:00
# else // HAVE_LIBVLC
2016-04-04 22:11:48 +08:00
Fatal ( " You must have vlc libraries installed to use vlc cameras for monitor %d " , id ) ;
2013-12-13 01:45:29 +08:00
# endif // HAVE_LIBVLC
2016-04-04 22:11:48 +08:00
}
else if ( type = = " cURL " )
{
2013-11-04 22:52:21 +08:00
# if HAVE_LIBCURL
2016-04-04 22:11:48 +08:00
camera = new cURLCamera (
id ,
path . c_str ( ) ,
user . c_str ( ) ,
pass . c_str ( ) ,
2016-04-28 21:20:56 +08:00
width ,
height ,
2016-04-04 22:11:48 +08:00
colours ,
brightness ,
contrast ,
hue ,
colour ,
2016-04-30 20:27:10 +08:00
purpose = = CAPTURE ,
record_audio
2016-04-04 22:11:48 +08:00
) ;
2013-11-04 22:52:21 +08:00
# else // HAVE_LIBCURL
2016-04-04 22:11:48 +08:00
Fatal ( " You must have libcurl installed to use ffmpeg cameras for monitor %d " , id ) ;
2013-11-04 22:52:21 +08:00
# endif // HAVE_LIBCURL
2016-04-04 22:11:48 +08:00
}
else
{
Fatal ( " Bogus monitor type '%s' for monitor %d " , type . c_str ( ) , id ) ;
}
monitor = new Monitor (
id ,
name . c_str ( ) ,
server_id ,
function ,
enabled ,
linked_monitors . c_str ( ) ,
camera ,
orientation ,
deinterlacing ,
2016-04-30 20:27:10 +08:00
savejpegs ,
videowriter ,
encoderparams ,
record_audio ,
2016-04-04 22:11:48 +08:00
event_prefix . c_str ( ) ,
label_format . c_str ( ) ,
Coord ( label_x , label_y ) ,
label_size ,
image_buffer_count ,
warmup_count ,
pre_event_count ,
post_event_count ,
stream_replay_buffer ,
alarm_frame_count ,
section_length ,
frame_skip ,
motion_frame_skip ,
analysis_fps ,
analysis_update_delay ,
capture_delay ,
alarm_capture_delay ,
fps_report_interval ,
ref_blend_perc ,
alarm_ref_blend_perc ,
track_motion ,
signal_check_colour ,
embed_exif ,
purpose ,
0 ,
0
) ;
int n_zones = 0 ;
if ( load_zones )
{
Zone * * zones = 0 ;
n_zones = Zone : : Load ( monitor , zones ) ;
monitor - > AddZones ( n_zones , zones ) ;
monitor - > AddPrivacyBitmask ( zones ) ;
}
Debug ( 1 , " Loaded monitor %d(%s), %d zones " , id , name . c_str ( ) , n_zones ) ;
return ( monitor ) ;
2003-03-26 19:57:29 +08:00
}
2009-01-28 17:48:06 +08:00
int Monitor : : Capture ( )
2003-03-26 19:57:29 +08:00
{
2016-04-04 22:11:48 +08:00
static int FirstCapture = 1 ;
int captureResult ;
int index = image_count % image_buffer_count ;
Image * capture_image = image_buffer [ index ] . image ;
if ( ( deinterlacing & 0xff ) = = 4 ) {
if ( FirstCapture ! = 1 ) {
/* Copy the next image into the shared memory */
capture_image - > CopyBuffer ( * ( next_buffer . image ) ) ;
}
/* Capture a new next image */
2016-04-30 20:27:10 +08:00
//Check if FFMPEG camera
if ( ( GetOptVideoWriter ( ) = = 2 ) & & camera - > SupportsNativeVideo ( ) ) {
captureResult = camera - > CaptureAndRecord ( * ( next_buffer . image ) , video_store_data - > recording , video_store_data - > event_file ) ;
} else {
captureResult = camera - > Capture ( * ( next_buffer . image ) ) ;
}
2016-04-04 22:11:48 +08:00
if ( FirstCapture ) {
FirstCapture = 0 ;
return 0 ;
}
} else {
2016-04-30 20:27:10 +08:00
//Check if FFMPEG camera
if ( ( GetOptVideoWriter ( ) = = 2 ) & & camera - > SupportsNativeVideo ( ) ) {
//Warning("ZMC: Recording: %d", video_store_data->recording);
captureResult = camera - > CaptureAndRecord ( * capture_image , video_store_data - > recording , video_store_data - > event_file ) ;
} else {
/* Capture directly into image buffer, avoiding the need to memcpy() */
captureResult = camera - > Capture ( * capture_image ) ;
}
2016-04-04 22:11:48 +08:00
}
2016-04-30 20:27:10 +08:00
if ( ( GetOptVideoWriter ( ) = = 2 ) & & captureResult > 0 )
{
//video_store_data->frameNumber = captureResult;
captureResult = 0 ;
}
2016-04-04 22:11:48 +08:00
if ( captureResult ! = 0 )
{
// Unable to capture image for temporary reason
// Fake a signal loss image
Rgb signalcolor ;
signalcolor = rgb_convert ( signal_check_colour , ZM_SUBPIX_ORDER_BGR ) ; /* HTML colour code is actually BGR in memory, we want RGB */
capture_image - > Fill ( signalcolor ) ;
captureResult = 0 ;
} else {
captureResult = 1 ;
}
if ( captureResult = = 1 )
{
/* Deinterlacing */
if ( ( deinterlacing & 0xff ) = = 1 ) {
capture_image - > Deinterlace_Discard ( ) ;
} else if ( ( deinterlacing & 0xff ) = = 2 ) {
capture_image - > Deinterlace_Linear ( ) ;
} else if ( ( deinterlacing & 0xff ) = = 3 ) {
capture_image - > Deinterlace_Blend ( ) ;
} else if ( ( deinterlacing & 0xff ) = = 4 ) {
capture_image - > Deinterlace_4Field ( next_buffer . image , ( deinterlacing > > 8 ) & 0xff ) ;
} else if ( ( deinterlacing & 0xff ) = = 5 ) {
capture_image - > Deinterlace_Blend_CustomRatio ( ( deinterlacing > > 8 ) & 0xff ) ;
2012-01-30 14:00:22 +08:00
}
2016-04-04 22:11:48 +08:00
if ( orientation ! = ROTATE_0 )
{
switch ( orientation )
{
case ROTATE_0 :
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
// No action required
break ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
case ROTATE_90 :
case ROTATE_180 :
case ROTATE_270 :
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
capture_image - > Rotate ( ( orientation - 1 ) * 90 ) ;
break ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
case FLIP_HORI :
case FLIP_VERT :
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
capture_image - > Flip ( orientation = = FLIP_HORI ) ;
break ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
2016-04-30 20:27:10 +08:00
} // end if captureResults == 1
2009-05-08 17:47:37 +08:00
2016-04-30 20:27:10 +08:00
// if true? let's get rid of this.
2016-04-04 22:11:48 +08:00
if ( true ) {
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( capture_image - > Size ( ) > camera - > ImageSize ( ) )
{
Error ( " Captured image %d does not match expected size %d check width, height and colour depth " , capture_image - > Size ( ) , camera - > ImageSize ( ) ) ;
return ( - 1 ) ;
}
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( ( ( unsigned int ) index = = shared_data - > last_read_index ) & & ( function > MONITOR ) )
{
Warning ( " Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size " , index , image_count ) ;
time_t now = time ( 0 ) ;
double approxFps = double ( image_buffer_count ) / double ( now - image_buffer [ index ] . timestamp - > tv_sec ) ;
time_t last_read_delta = now - shared_data - > last_read_time ;
if ( last_read_delta > ( image_buffer_count / approxFps ) )
{
Warning ( " Last image read from shared memory %ld seconds ago, zma may have gone away " , last_read_delta )
shared_data - > last_read_index = image_buffer_count ;
}
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
if ( privacy_bitmask )
capture_image - > MaskPrivacy ( privacy_bitmask ) ;
gettimeofday ( image_buffer [ index ] . timestamp , NULL ) ;
if ( config . timestamp_on_capture )
{
TimestampImage ( capture_image , image_buffer [ index ] . timestamp ) ;
}
shared_data - > signal = CheckSignal ( capture_image ) ;
shared_data - > last_write_index = index ;
shared_data - > last_write_time = image_buffer [ index ] . timestamp - > tv_sec ;
image_count + + ;
if ( image_count & & fps_report_interval & & ! ( image_count % fps_report_interval ) )
{
time_t now = image_buffer [ index ] . timestamp - > tv_sec ;
fps = double ( fps_report_interval ) / ( now - last_fps_time ) ;
//Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time );
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
Info ( " %s: %d - Capturing at %.2lf fps " , name , image_count , fps ) ;
last_fps_time = now ;
}
if ( shared_data - > action & GET_SETTINGS )
{
shared_data - > brightness = camera - > Brightness ( ) ;
shared_data - > hue = camera - > Hue ( ) ;
shared_data - > colour = camera - > Colour ( ) ;
shared_data - > contrast = camera - > Contrast ( ) ;
shared_data - > action & = ~ GET_SETTINGS ;
}
if ( shared_data - > action & SET_SETTINGS )
{
camera - > Brightness ( shared_data - > brightness ) ;
camera - > Hue ( shared_data - > hue ) ;
camera - > Colour ( shared_data - > colour ) ;
camera - > Contrast ( shared_data - > contrast ) ;
shared_data - > action & = ~ SET_SETTINGS ;
}
return ( 0 ) ;
}
shared_data - > signal = false ;
return ( - 1 ) ;
2016-04-06 05:14:46 +08:00
}
void Monitor : : TimestampImage ( Image * ts_image , const struct timeval * ts_time ) const
{
2016-04-04 22:11:48 +08:00
if ( label_format [ 0 ] )
{
// Expand the strftime macros first
char label_time_text [ 256 ] ;
strftime ( label_time_text , sizeof ( label_time_text ) , label_format , localtime ( & ts_time - > tv_sec ) ) ;
char label_text [ 1024 ] ;
const char * s_ptr = label_time_text ;
char * d_ptr = label_text ;
while ( * s_ptr & & ( ( d_ptr - label_text ) < ( unsigned int ) sizeof ( label_text ) ) )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( * s_ptr = = ' % ' )
{
bool found_macro = false ;
switch ( * ( s_ptr + 1 ) )
2006-12-25 00:50:01 +08:00
{
2016-04-04 22:11:48 +08:00
case ' N ' :
d_ptr + = snprintf ( d_ptr , sizeof ( label_text ) - ( d_ptr - label_text ) , " %s " , name ) ;
found_macro = true ;
break ;
case ' Q ' :
d_ptr + = snprintf ( d_ptr , sizeof ( label_text ) - ( d_ptr - label_text ) , " %s " , trigger_data - > trigger_showtext ) ;
found_macro = true ;
break ;
case ' f ' :
d_ptr + = snprintf ( d_ptr , sizeof ( label_text ) - ( d_ptr - label_text ) , " %02ld " , ts_time - > tv_usec / 10000 ) ;
found_macro = true ;
break ;
}
if ( found_macro )
{
s_ptr + = 2 ;
continue ;
2006-12-25 00:50:01 +08:00
}
2016-04-04 22:11:48 +08:00
}
* d_ptr + + = * s_ptr + + ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
* d_ptr = ' \0 ' ;
ts_image - > Annotate ( label_text , label_coord , label_size ) ;
}
2016-04-06 05:14:46 +08:00
}
bool Monitor : : closeEvent ( )
{
2016-04-30 20:27:10 +08:00
video_store_data - > recording = false ;
2016-04-04 22:11:48 +08:00
if ( event )
{
if ( function = = RECORD | | function = = MOCORD )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
gettimeofday ( & ( event - > EndTime ( ) ) , NULL ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
delete event ;
event = 0 ;
return ( true ) ;
}
return ( false ) ;
2016-04-06 05:14:46 +08:00
}
2008-10-06 03:07:43 +08:00
unsigned int Monitor : : DetectMotion ( const Image & comp_image , Event : : StringSet & zoneSet )
2003-03-26 19:57:29 +08:00
{
2016-04-04 22:11:48 +08:00
bool alarm = false ;
unsigned int score = 0 ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( n_zones < = 0 ) return ( alarm ) ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
if ( config . record_diag_images )
{
static char diag_path [ PATH_MAX ] = " " ;
if ( ! diag_path [ 0 ] )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
snprintf ( diag_path , sizeof ( diag_path ) , " %s/%d/diag-r.jpg " , config . dir_events , id ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
ref_image . WriteJpeg ( diag_path ) ;
}
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
ref_image . Delta ( comp_image , & delta_image ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
if ( config . record_diag_images )
{
static char diag_path [ PATH_MAX ] = " " ;
if ( ! diag_path [ 0 ] )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
snprintf ( diag_path , sizeof ( diag_path ) , " %s/%d/diag-d.jpg " , config . dir_events , id ) ;
}
delta_image . WriteJpeg ( diag_path ) ;
}
// Blank out all exclusion zones
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
// need previous alarmed state for preclusive zone, so don't clear just yet
if ( ! zone - > IsPreclusive ( ) )
zone - > ClearAlarm ( ) ;
if ( ! zone - > IsInactive ( ) )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
continue ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
Debug ( 3 , " Blanking inactive zone %s " , zone - > Label ( ) ) ;
delta_image . Fill ( RGB_BLACK , zone - > GetPolygon ( ) ) ;
}
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
// Check preclusive zones first
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
if ( ! zone - > IsPreclusive ( ) )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
continue ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
int old_zone_score = zone - > Score ( ) ;
bool old_zone_alarmed = zone - > Alarmed ( ) ;
Debug ( 3 , " Checking preclusive zone %s - old score: %d, state: %s " , zone - > Label ( ) , old_zone_score , zone - > Alarmed ( ) ? " alarmed " : " quiet " ) ;
if ( zone - > CheckAlarms ( & delta_image ) )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
alarm = true ;
score + = zone - > Score ( ) ;
zone - > SetAlarm ( ) ;
Debug ( 3 , " Zone is alarmed, zone score = %d " , zone - > Score ( ) ) ;
zoneSet . insert ( zone - > Label ( ) ) ;
//zone->ResetStats();
} else {
// check if end of alarm
if ( old_zone_alarmed ) {
Debug ( 3 , " Preclusive Zone %s alarm Ends. Prevíous score: %d " , zone - > Label ( ) , old_zone_score ) ;
if ( old_zone_score > 0 ) {
zone - > SetExtendAlarmCount ( zone - > GetExtendAlarmFrames ( ) ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
if ( zone - > CheckExtendAlarmCount ( ) ) {
alarm = true ;
zone - > SetAlarm ( ) ;
} else {
zone - > ClearAlarm ( ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
}
Coord alarm_centre ;
int top_score = - 1 ;
if ( alarm )
{
alarm = false ;
score = 0 ;
}
else
{
// Find all alarm pixels in active zones
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
if ( ! zone - > IsActive ( ) | | zone - > IsPreclusive ( ) )
{
continue ;
}
Debug ( 3 , " Checking active 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 ( ) ) ;
zoneSet . insert ( zone - > Label ( ) ) ;
if ( config . opt_control & & track_motion )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( ( int ) zone - > Score ( ) > top_score )
{
top_score = zone - > Score ( ) ;
alarm_centre = zone - > GetAlarmCentre ( ) ;
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
if ( alarm )
{
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
if ( ! zone - > IsInclusive ( ) )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
continue ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
Debug ( 3 , " Checking inclusive zone %s " , zone - > Label ( ) ) ;
if ( zone - > CheckAlarms ( & delta_image ) )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
alarm = true ;
score + = zone - > Score ( ) ;
zone - > SetAlarm ( ) ;
Debug ( 3 , " Zone is alarmed, zone score = %d " , zone - > Score ( ) ) ;
zoneSet . insert ( zone - > Label ( ) ) ;
if ( config . opt_control & & track_motion )
{
if ( zone - > Score ( ) > ( unsigned int ) top_score )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
top_score = zone - > Score ( ) ;
alarm_centre = zone - > GetAlarmCentre ( ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
else
{
// Find all alarm pixels in exclusive zones
for ( int n_zone = 0 ; n_zone < n_zones ; n_zone + + )
{
Zone * zone = zones [ n_zone ] ;
if ( ! zone - > IsExclusive ( ) )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
continue ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
Debug ( 3 , " Checking exclusive zone %s " , zone - > Label ( ) ) ;
if ( zone - > CheckAlarms ( & delta_image ) )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
alarm = true ;
score + = zone - > Score ( ) ;
zone - > SetAlarm ( ) ;
Debug ( 3 , " Zone is alarmed, zone score = %d " , zone - > Score ( ) ) ;
zoneSet . insert ( zone - > Label ( ) ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
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
return ( score ? score : alarm ) ;
2003-03-26 19:57:29 +08:00
}
2005-12-23 00:46:25 +08:00
bool Monitor : : DumpSettings ( char * output , bool verbose )
{
2016-04-04 22:11:48 +08:00
output [ 0 ] = 0 ;
2009-05-08 17:47:37 +08:00
2016-04-04 22:11:48 +08:00
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 " : ( camera - > IsRemote ( ) ? " Remote " : " File " ) ) ;
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L
2016-04-04 22:11:48 +08:00
if ( camera - > IsLocal ( ) )
{
sprintf ( output + strlen ( output ) , " Device : %s \n " , ( ( LocalCamera * ) camera ) - > Device ( ) . c_str ( ) ) ;
sprintf ( output + strlen ( output ) , " Channel : %d \n " , ( ( LocalCamera * ) camera ) - > Channel ( ) ) ;
sprintf ( output + strlen ( output ) , " Standard : %d \n " , ( ( LocalCamera * ) camera ) - > Standard ( ) ) ;
}
else
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L
2016-04-04 22:11:48 +08:00
if ( camera - > IsRemote ( ) )
{
sprintf ( output + strlen ( output ) , " Protocol : %s \n " , ( ( RemoteCamera * ) camera ) - > Protocol ( ) . c_str ( ) ) ;
sprintf ( output + strlen ( output ) , " Host : %s \n " , ( ( RemoteCamera * ) camera ) - > Host ( ) . c_str ( ) ) ;
sprintf ( output + strlen ( output ) , " Port : %s \n " , ( ( RemoteCamera * ) camera ) - > Port ( ) . c_str ( ) ) ;
sprintf ( output + strlen ( output ) , " Path : %s \n " , ( ( RemoteCamera * ) camera ) - > Path ( ) . c_str ( ) ) ;
}
else if ( camera - > IsFile ( ) )
{
sprintf ( output + strlen ( output ) , " Path : %s \n " , ( ( FileCamera * ) camera ) - > Path ( ) ) ;
}
2009-01-28 23:02:33 +08:00
# if HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
else if ( camera - > IsFfmpeg ( ) )
{
sprintf ( output + strlen ( output ) , " Path : %s \n " , ( ( FfmpegCamera * ) camera ) - > Path ( ) . c_str ( ) ) ;
}
2009-01-28 23:02:33 +08:00
# endif // HAVE_LIBAVFORMAT
2016-04-04 22:11:48 +08:00
sprintf ( output + strlen ( output ) , " Width : %d \n " , camera - > Width ( ) ) ;
sprintf ( output + strlen ( output ) , " Height : %d \n " , camera - > Height ( ) ) ;
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L
2016-04-04 22:11:48 +08:00
if ( camera - > IsLocal ( ) )
{
sprintf ( output + strlen ( output ) , " Palette : %d \n " , ( ( LocalCamera * ) camera ) - > Palette ( ) ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L
2016-04-04 22:11:48 +08:00
sprintf ( output + strlen ( output ) , " Colours : %d \n " , camera - > Colours ( ) ) ;
sprintf ( output + strlen ( output ) , " Subpixel Order : %d \n " , camera - > SubpixelOrder ( ) ) ;
sprintf ( output + strlen ( output ) , " Event Prefix : %s \n " , event_prefix ) ;
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 ( ) ) ;
sprintf ( output + strlen ( output ) , " Label Size : %d \n " , label_size ) ;
sprintf ( output + strlen ( output ) , " Image Buffer Count : %d \n " , image_buffer_count ) ;
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 ) ;
sprintf ( output + strlen ( output ) , " Stream Replay Buffer : %d \n " , stream_replay_buffer ) ;
sprintf ( output + strlen ( output ) , " Alarm Frame Count : %d \n " , alarm_frame_count ) ;
sprintf ( output + strlen ( output ) , " Section Length : %d \n " , section_length ) ;
sprintf ( output + strlen ( output ) , " Maximum FPS : %.2f \n " , capture_delay ? DT_PREC_3 / capture_delay : 0.0 ) ;
sprintf ( output + strlen ( output ) , " Alarm Maximum FPS : %.2f \n " , alarm_capture_delay ? DT_PREC_3 / alarm_capture_delay : 0.0 ) ;
sprintf ( output + strlen ( output ) , " Reference Blend %%ge : %d \n " , ref_blend_perc ) ;
sprintf ( output + strlen ( output ) , " Alarm Reference Blend %%ge : %d \n " , alarm_ref_blend_perc ) ;
sprintf ( output + strlen ( output ) , " Track Motion : %d \n " , track_motion ) ;
sprintf ( output + strlen ( output ) , " Function: %d - %s \n " , function ,
function = = NONE ? " None " : (
function = = MONITOR ? " Monitor Only " : (
function = = MODECT ? " Motion Detection " : (
function = = RECORD ? " Continuous Record " : (
function = = MOCORD ? " Continuous Record with Motion Detection " : (
function = = NODECT ? " Externally Triggered only, no Motion Detection " : " Unknown "
) ) ) ) ) ) ;
sprintf ( output + strlen ( output ) , " Zones : %d \n " , n_zones ) ;
for ( int i = 0 ; i < n_zones ; i + + )
{
zones [ i ] - > DumpSettings ( output + strlen ( output ) , verbose ) ;
}
return ( true ) ;
2016-04-06 05:14:46 +08:00
} // bool Monitor::DumpSettings( char *output, bool verbose )
2006-01-23 02:31:55 +08:00
2007-08-30 02:11:09 +08:00
bool MonitorStream : : checkSwapPath ( const char * path , bool create_path )
{
2016-04-04 22:11:48 +08:00
uid_t uid = getuid ( ) ;
gid_t gid = getgid ( ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
struct stat stat_buf ;
if ( stat ( path , & stat_buf ) < 0 )
{
if ( create_path & & errno = = ENOENT )
{
Debug ( 3 , " Swap path '%s' missing, creating " , path ) ;
if ( mkdir ( path , 0755 ) )
{
Error ( " Can't mkdir %s: %s " , path , strerror ( errno ) ) ;
return ( false ) ;
}
if ( stat ( path , & stat_buf ) < 0 )
{
Error ( " Can't stat '%s': %s " , path , strerror ( errno ) ) ;
return ( false ) ;
}
}
2008-10-30 07:08:21 +08:00
else
2016-04-04 22:11:48 +08:00
{
Error ( " Can't stat '%s': %s " , path , strerror ( errno ) ) ;
return ( false ) ;
}
}
if ( ! S_ISDIR ( stat_buf . st_mode ) )
{
Error ( " Swap image path '%s' is not a directory " , path ) ;
return ( false ) ;
}
mode_t mask = 0 ;
if ( uid = = stat_buf . st_uid )
{
// If we are the owner
mask = 00700 ;
}
else if ( gid = = stat_buf . st_gid )
{
// If we are in the owner group
mask = 00070 ;
}
else
{
// We are neither the owner nor in the group
mask = 00007 ;
}
if ( ( stat_buf . st_mode & mask ) ! = mask )
{
Error ( " Insufficient permissions on swap image path '%s' " , path ) ;
return ( false ) ;
}
return ( true ) ;
2007-08-30 02:11:09 +08:00
}
void MonitorStream : : processCommand ( const CmdMsg * msg )
{
2016-04-04 22:11:48 +08:00
Debug ( 2 , " Got message, type %d, msg %d " , msg - > msg_type , msg - > msg_data [ 0 ] ) ;
// Check for incoming command
switch ( ( MsgCommand ) msg - > msg_data [ 0 ] )
{
case CMD_PAUSE :
{
Debug ( 1 , " Got PAUSE command " ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
// Set paused flag
paused = true ;
// Set delayed flag
delayed = true ;
last_frame_sent = TV_2_FLOAT ( now ) ;
break ;
}
case CMD_PLAY :
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
Debug ( 1 , " Got PLAY command " ) ;
if ( paused )
{
// Clear paused flag
paused = false ;
// Set delayed_play flag
delayed = true ;
}
replay_rate = ZM_RATE_BASE ;
break ;
}
case CMD_VARPLAY :
{
Debug ( 1 , " Got VARPLAY command " ) ;
if ( paused )
{
// Clear paused flag
paused = false ;
// Set delayed_play flag
delayed = true ;
}
replay_rate = ntohs ( ( ( unsigned char ) msg - > msg_data [ 2 ] < < 8 ) | ( unsigned char ) msg - > msg_data [ 1 ] ) - 32768 ;
break ;
}
case CMD_STOP :
{
Debug ( 1 , " Got STOP command " ) ;
// Clear paused flag
paused = false ;
// Clear delayed_play flag
delayed = false ;
break ;
}
case CMD_FASTFWD :
{
Debug ( 1 , " Got FAST FWD command " ) ;
if ( paused )
{
// Clear paused flag
paused = false ;
// Set delayed_play flag
delayed = true ;
}
// Set play rate
switch ( replay_rate )
{
case 2 * ZM_RATE_BASE :
replay_rate = 5 * ZM_RATE_BASE ;
break ;
case 5 * ZM_RATE_BASE :
replay_rate = 10 * ZM_RATE_BASE ;
break ;
case 10 * ZM_RATE_BASE :
replay_rate = 25 * ZM_RATE_BASE ;
break ;
case 25 * ZM_RATE_BASE :
case 50 * ZM_RATE_BASE :
replay_rate = 50 * ZM_RATE_BASE ;
break ;
default :
replay_rate = 2 * ZM_RATE_BASE ;
break ;
}
break ;
}
case CMD_SLOWFWD :
{
Debug ( 1 , " Got SLOW FWD command " ) ;
// Set paused flag
paused = true ;
// Set delayed flag
delayed = true ;
// Set play rate
replay_rate = ZM_RATE_BASE ;
// Set step
step = 1 ;
break ;
}
case CMD_SLOWREV :
{
Debug ( 1 , " Got SLOW REV command " ) ;
// Set paused flag
paused = true ;
// Set delayed flag
delayed = true ;
// Set play rate
replay_rate = ZM_RATE_BASE ;
// Set step
step = - 1 ;
break ;
}
case CMD_FASTREV :
{
Debug ( 1 , " Got FAST REV command " ) ;
if ( paused )
{
// Clear paused flag
paused = false ;
// Set delayed_play flag
delayed = true ;
}
// Set play rate
switch ( replay_rate )
{
case - 2 * ZM_RATE_BASE :
replay_rate = - 5 * ZM_RATE_BASE ;
break ;
case - 5 * ZM_RATE_BASE :
replay_rate = - 10 * ZM_RATE_BASE ;
break ;
case - 10 * ZM_RATE_BASE :
replay_rate = - 25 * ZM_RATE_BASE ;
break ;
case - 25 * ZM_RATE_BASE :
case - 50 * ZM_RATE_BASE :
replay_rate = - 50 * ZM_RATE_BASE ;
break ;
default :
replay_rate = - 2 * ZM_RATE_BASE ;
break ;
}
break ;
}
case CMD_ZOOMIN :
{
x = ( ( unsigned char ) msg - > msg_data [ 1 ] < < 8 ) | ( unsigned char ) msg - > msg_data [ 2 ] ;
y = ( ( unsigned char ) msg - > msg_data [ 3 ] < < 8 ) | ( unsigned char ) msg - > msg_data [ 4 ] ;
Debug ( 1 , " Got ZOOM IN command, to %d,%d " , x , y ) ;
switch ( zoom )
{
case 100 :
zoom = 150 ;
break ;
case 150 :
zoom = 200 ;
break ;
case 200 :
zoom = 300 ;
break ;
case 300 :
zoom = 400 ;
break ;
case 400 :
default :
zoom = 500 ;
break ;
}
break ;
}
case CMD_ZOOMOUT :
{
Debug ( 1 , " Got ZOOM OUT command " ) ;
switch ( zoom )
{
case 500 :
zoom = 400 ;
break ;
case 400 :
zoom = 300 ;
break ;
case 300 :
zoom = 200 ;
break ;
case 200 :
zoom = 150 ;
break ;
case 150 :
default :
zoom = 100 ;
break ;
}
break ;
}
case CMD_PAN :
{
x = ( ( unsigned char ) msg - > msg_data [ 1 ] < < 8 ) | ( unsigned char ) msg - > msg_data [ 2 ] ;
y = ( ( unsigned char ) msg - > msg_data [ 3 ] < < 8 ) | ( unsigned char ) msg - > msg_data [ 4 ] ;
Debug ( 1 , " Got PAN command, to %d,%d " , x , y ) ;
break ;
}
case CMD_SCALE :
{
scale = ( ( unsigned char ) msg - > msg_data [ 1 ] < < 8 ) | ( unsigned char ) msg - > msg_data [ 2 ] ;
Debug ( 1 , " Got SCALE command, to %d " , scale ) ;
break ;
}
case CMD_QUIT :
{
Info ( " User initiated exit - CMD_QUIT " ) ;
break ;
}
case CMD_QUERY :
{
Debug ( 1 , " Got QUERY command, sending STATUS " ) ;
break ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
default :
{
Error ( " Got unexpected command %d " , msg - > msg_data [ 0 ] ) ;
break ;
}
}
struct {
int id ;
int state ;
double fps ;
int buffer_level ;
int rate ;
double delay ;
int zoom ;
bool delayed ;
bool paused ;
bool enabled ;
bool forced ;
} status_data ;
status_data . id = monitor - > Id ( ) ;
status_data . fps = monitor - > GetFPS ( ) ;
status_data . state = monitor - > shared_data - > state ;
if ( playback_buffer > 0 )
status_data . buffer_level = ( MOD_ADD ( ( temp_write_index - temp_read_index ) , 0 , temp_image_buffer_count ) * 100 ) / temp_image_buffer_count ;
else
status_data . buffer_level = 0 ;
status_data . delayed = delayed ;
status_data . paused = paused ;
status_data . rate = replay_rate ;
status_data . delay = TV_2_FLOAT ( now ) - TV_2_FLOAT ( last_frame_timestamp ) ;
status_data . zoom = zoom ;
//status_data.enabled = monitor->shared_data->active;
status_data . enabled = monitor - > trigger_data - > trigger_state ! = Monitor : : TRIGGER_OFF ;
status_data . forced = monitor - > trigger_data - > trigger_state = = Monitor : : TRIGGER_ON ;
Debug ( 2 , " L:%d, D:%d, P:%d, R:%d, d:%.3f, Z:%d, E:%d F:%d " ,
status_data . buffer_level ,
status_data . delayed ,
status_data . paused ,
status_data . rate ,
status_data . delay ,
status_data . zoom ,
status_data . enabled ,
status_data . forced
) ;
DataMsg status_msg ;
status_msg . msg_type = MSG_DATA_WATCH ;
memcpy ( & status_msg . msg_data , & status_data , sizeof ( status_data ) ) ;
int nbytes = 0 ;
if ( ( nbytes = sendto ( sd , & status_msg , sizeof ( status_msg ) , MSG_DONTWAIT , ( sockaddr * ) & rem_addr , sizeof ( rem_addr ) ) ) < 0 )
{
//if ( errno != EAGAIN )
{
Error ( " Can't sendto on sd %d: %s " , sd , strerror ( errno ) ) ;
//exit( -1 );
}
}
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
// quit after sending a status, if this was a quit request
if ( ( MsgCommand ) msg - > msg_data [ 0 ] = = CMD_QUIT )
exit ( 0 ) ;
2016-01-29 22:58:57 +08:00
2016-04-04 22:11:48 +08:00
updateFrameRate ( monitor - > GetFPS ( ) ) ;
2007-08-30 02:11:09 +08:00
}
2009-01-22 01:37:39 +08:00
bool MonitorStream : : sendFrame ( const char * filepath , struct timeval * timestamp )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
bool send_raw = ( ( scale > = ZM_SCALE_BASE ) & & ( zoom = = ZM_SCALE_BASE ) ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
if ( type ! = STREAM_JPEG )
send_raw = false ;
if ( ! config . timestamp_on_capture & & timestamp )
send_raw = false ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
if ( ! send_raw )
{
Image temp_image ( filepath ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
return ( sendFrame ( & temp_image , timestamp ) ) ;
}
else
{
int img_buffer_size = 0 ;
static unsigned char img_buffer [ ZM_MAX_IMAGE_SIZE ] ;
FILE * fdj = NULL ;
if ( ( fdj = fopen ( filepath , " r " ) ) )
{
img_buffer_size = fread ( img_buffer , 1 , sizeof ( img_buffer ) , fdj ) ;
fclose ( fdj ) ;
2007-08-30 02:11:09 +08:00
}
else
{
2016-04-04 22:11:48 +08:00
Error ( " Can't open %s: %s " , filepath , strerror ( errno ) ) ;
return ( false ) ;
}
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
// Calculate how long it takes to actually send the frame
struct timeval frameStartTime ;
gettimeofday ( & frameStartTime , NULL ) ;
fprintf ( stdout , " --ZoneMinderFrame \r \n " ) ;
fprintf ( stdout , " Content-Length: %d \r \n " , img_buffer_size ) ;
fprintf ( stdout , " Content-Type: image/jpeg \r \n \r \n " ) ;
if ( fwrite ( img_buffer , img_buffer_size , 1 , stdout ) ! = 1 )
{
if ( ! zm_terminate )
Error ( " Unable to send stream frame: %s " , strerror ( errno ) ) ;
return ( false ) ;
}
fprintf ( stdout , " \r \n \r \n " ) ;
fflush ( stdout ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
struct timeval frameEndTime ;
gettimeofday ( & frameEndTime , NULL ) ;
2009-04-03 20:10:54 +08:00
2016-04-04 22:11:48 +08:00
int frameSendTime = tvDiffMsec ( frameStartTime , frameEndTime ) ;
if ( frameSendTime > 1000 / maxfps )
{
maxfps / = 2 ;
Error ( " Frame send time %d msec too slow, throttling maxfps to %.2f " , frameSendTime , maxfps ) ;
}
2009-04-03 20:10:54 +08:00
2016-04-04 22:11:48 +08:00
last_frame_sent = TV_2_FLOAT ( now ) ;
2009-01-22 01:37:39 +08:00
2016-04-04 22:11:48 +08:00
return ( true ) ;
}
return ( false ) ;
2007-08-30 02:11:09 +08:00
}
2009-01-22 01:37:39 +08:00
bool MonitorStream : : sendFrame ( Image * image , struct timeval * timestamp )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
Image * send_image = prepareImage ( image ) ;
if ( ! config . timestamp_on_capture & & timestamp )
monitor - > TimestampImage ( send_image , timestamp ) ;
2007-08-30 02:11:09 +08:00
# if HAVE_LIBAVCODEC
2016-04-04 22:11:48 +08:00
if ( type = = STREAM_MPEG )
{
if ( ! vid_stream )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
vid_stream = new VideoStream ( " pipe: " , format , bitrate , effective_fps , send_image - > Colours ( ) , send_image - > SubpixelOrder ( ) , send_image - > Width ( ) , send_image - > Height ( ) ) ;
fprintf ( stdout , " Content-type: %s \r \n \r \n " , vid_stream - > MimeType ( ) ) ;
vid_stream - > OpenStream ( ) ;
}
static struct timeval base_time ;
struct DeltaTimeval delta_time ;
if ( ! frame_count )
base_time = * timestamp ;
DELTA_TIMEVAL ( delta_time , * timestamp , base_time , DT_PREC_3 ) ;
/* double pts = */ vid_stream - > EncodeFrame ( send_image - > Buffer ( ) , send_image - > Size ( ) , config . mpeg_timed_frames , delta_time . delta ) ;
}
else
2007-08-30 02:11:09 +08:00
# endif // HAVE_LIBAVCODEC
2016-04-04 22:11:48 +08:00
{
static unsigned char temp_img_buffer [ ZM_MAX_IMAGE_SIZE ] ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
int img_buffer_size = 0 ;
unsigned char * img_buffer = temp_img_buffer ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
// Calculate how long it takes to actually send the frame
struct timeval frameStartTime ;
gettimeofday ( & frameStartTime , NULL ) ;
fprintf ( stdout , " --ZoneMinderFrame \r \n " ) ;
switch ( type )
{
case STREAM_JPEG :
send_image - > EncodeJpeg ( img_buffer , & img_buffer_size ) ;
fprintf ( stdout , " Content-Type: image/jpeg \r \n " ) ;
break ;
case STREAM_RAW :
fprintf ( stdout , " Content-Type: image/x-rgb \r \n " ) ;
img_buffer = ( uint8_t * ) send_image - > Buffer ( ) ;
img_buffer_size = send_image - > Size ( ) ;
break ;
case STREAM_ZIP :
fprintf ( stdout , " Content-Type: image/x-rgbz \r \n " ) ;
unsigned long zip_buffer_size ;
send_image - > Zip ( img_buffer , & zip_buffer_size ) ;
img_buffer_size = zip_buffer_size ;
break ;
default :
Fatal ( " Unexpected frame type %d " , type ) ;
break ;
}
fprintf ( stdout , " Content-Length: %d \r \n \r \n " , img_buffer_size ) ;
if ( fwrite ( img_buffer , img_buffer_size , 1 , stdout ) ! = 1 )
{
if ( ! zm_terminate )
Error ( " Unable to send stream frame: %s " , strerror ( errno ) ) ;
return ( false ) ;
}
fprintf ( stdout , " \r \n \r \n " ) ;
fflush ( stdout ) ;
2009-04-03 20:10:54 +08:00
2016-04-04 22:11:48 +08:00
struct timeval frameEndTime ;
gettimeofday ( & frameEndTime , NULL ) ;
2009-04-03 20:10:54 +08:00
2016-04-04 22:11:48 +08:00
int frameSendTime = tvDiffMsec ( frameStartTime , frameEndTime ) ;
if ( frameSendTime > 1000 / maxfps )
{
maxfps / = 1.5 ;
Error ( " Frame send time %d msec too slow, throttling maxfps to %.2f " , frameSendTime , maxfps ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
last_frame_sent = TV_2_FLOAT ( now ) ;
return ( true ) ;
2007-08-30 02:11:09 +08:00
}
void MonitorStream : : runStream ( )
{
2016-04-04 22:11:48 +08:00
if ( type = = STREAM_SINGLE )
{
// Not yet migrated over to stream class
monitor - > SingleImage ( scale ) ;
return ;
}
2007-11-11 23:57:54 +08:00
2016-04-04 22:11:48 +08:00
openComms ( ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
checkInitialised ( ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
updateFrameRate ( monitor - > GetFPS ( ) ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
if ( type = = STREAM_JPEG )
fprintf ( stdout , " Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame \r \n \r \n " ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
int last_read_index = monitor - > image_buffer_count ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
time_t stream_start_time ;
time ( & stream_start_time ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
frame_count = 0 ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
temp_image_buffer = 0 ;
temp_image_buffer_count = playback_buffer ;
temp_read_index = temp_image_buffer_count ;
temp_write_index = temp_image_buffer_count ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
char * swap_path = 0 ;
bool buffered_playback = false ;
2015-08-27 23:14:00 +08:00
2016-04-04 22:11:48 +08:00
// 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id
const int max_swap_len_suffix = 15 ;
2015-11-22 02:17:23 +08:00
2016-04-04 22:11:48 +08:00
int swap_path_length = strlen ( config . path_swap ) + 1 ; // +1 for NULL terminator
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
if ( connkey & & playback_buffer > 0 ) {
if ( swap_path_length + max_swap_len_suffix > PATH_MAX ) {
Error ( " Swap Path is too long. %d > %d " , swap_path_length + max_swap_len_suffix , PATH_MAX ) ;
} else {
swap_path = ( char * ) malloc ( swap_path_length + max_swap_len_suffix ) ;
Debug ( 3 , " Checking swap image path %s " , config . path_swap ) ;
strncpy ( swap_path , config . path_swap , swap_path_length ) ;
if ( checkSwapPath ( swap_path , false ) ) {
snprintf ( & ( swap_path [ swap_path_length ] ) , max_swap_len_suffix , " /zmswap-m%d " , monitor - > Id ( ) ) ;
if ( checkSwapPath ( swap_path , true ) ) {
snprintf ( & ( swap_path [ swap_path_length ] ) , max_swap_len_suffix , " /zmswap-q%06d " , connkey ) ;
if ( checkSwapPath ( swap_path , true ) ) {
buffered_playback = true ;
}
}
}
if ( ! buffered_playback ) {
Error ( " Unable to validate swap image path, disabling buffered playback " ) ;
} else {
Debug ( 2 , " Assigning temporary buffer " ) ;
temp_image_buffer = new SwapImage [ temp_image_buffer_count ] ;
memset ( temp_image_buffer , 0 , sizeof ( * temp_image_buffer ) * temp_image_buffer_count ) ;
Debug ( 2 , " Assigned temporary buffer " ) ;
}
}
}
float max_secs_since_last_sent_frame = 10.0 ; //should be > keep alive amount (5 secs)
while ( ! zm_terminate )
{
bool got_command = false ;
if ( feof ( stdout ) | | ferror ( stdout ) | | ! monitor - > ShmValid ( ) )
{
break ;
}
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
gettimeofday ( & now , NULL ) ;
2015-01-14 04:16:38 +08:00
2016-04-04 22:11:48 +08:00
if ( connkey )
{
while ( checkCommandQueue ( ) ) {
got_command = true ;
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
//bool frame_sent = false;
if ( buffered_playback & & delayed )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
if ( temp_read_index = = temp_write_index )
{
// Go back to live viewing
Debug ( 1 , " Exceeded temporary streaming buffer " ) ;
// Clear paused flag
paused = false ;
// Clear delayed_play flag
delayed = false ;
replay_rate = ZM_RATE_BASE ;
}
else
{
if ( ! paused )
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
int temp_index = MOD_ADD ( temp_read_index , 0 , temp_image_buffer_count ) ;
//Debug( 3, "tri: %d, ti: %d", temp_read_index, temp_index );
SwapImage * swap_image = & temp_image_buffer [ temp_index ] ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
if ( ! swap_image - > valid )
{
paused = true ;
delayed = true ;
temp_read_index = MOD_ADD ( temp_read_index , ( replay_rate > = 0 ? - 1 : 1 ) , temp_image_buffer_count ) ;
}
else
{
//Debug( 3, "siT: %f, lfT: %f", TV_2_FLOAT( swap_image->timestamp ), TV_2_FLOAT( last_frame_timestamp ) );
double expected_delta_time = ( ( TV_2_FLOAT ( swap_image - > timestamp ) - TV_2_FLOAT ( last_frame_timestamp ) ) * ZM_RATE_BASE ) / replay_rate ;
double actual_delta_time = TV_2_FLOAT ( now ) - last_frame_sent ;
//Debug( 3, "eDT: %.3lf, aDT: %.3f, lFS:%.3f, NOW:%.3f", expected_delta_time, actual_delta_time, last_frame_sent, TV_2_FLOAT( now ) );
// If the next frame is due
if ( actual_delta_time > expected_delta_time )
{
//Debug( 2, "eDT: %.3lf, aDT: %.3f", expected_delta_time, actual_delta_time );
if ( temp_index % frame_mod = = 0 )
{
Debug ( 2 , " Sending delayed frame %d " , temp_index ) ;
// Send the next frame
if ( ! sendFrame ( temp_image_buffer [ temp_index ] . file_name , & temp_image_buffer [ temp_index ] . timestamp ) )
zm_terminate = true ;
memcpy ( & last_frame_timestamp , & ( swap_image - > timestamp ) , sizeof ( last_frame_timestamp ) ) ;
//frame_sent = true;
}
temp_read_index = MOD_ADD ( temp_read_index , ( replay_rate > 0 ? 1 : - 1 ) , temp_image_buffer_count ) ;
2012-03-22 14:30:57 +08:00
}
2016-04-04 22:11:48 +08:00
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
else if ( step ! = 0 )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
temp_read_index = MOD_ADD ( temp_read_index , ( step > 0 ? 1 : - 1 ) , temp_image_buffer_count ) ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
SwapImage * swap_image = & temp_image_buffer [ temp_read_index ] ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
// Send the next frame
if ( ! sendFrame ( temp_image_buffer [ temp_read_index ] . file_name , & temp_image_buffer [ temp_read_index ] . timestamp ) )
zm_terminate = true ;
memcpy ( & last_frame_timestamp , & ( swap_image - > timestamp ) , sizeof ( last_frame_timestamp ) ) ;
//frame_sent = true;
step = 0 ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
else
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
int temp_index = MOD_ADD ( temp_read_index , 0 , temp_image_buffer_count ) ;
double actual_delta_time = TV_2_FLOAT ( now ) - last_frame_sent ;
if ( got_command | | actual_delta_time > 5 )
{
// Send keepalive
Debug ( 2 , " Sending keepalive frame %d " , temp_index ) ;
// Send the next frame
if ( ! sendFrame ( temp_image_buffer [ temp_index ] . file_name , & temp_image_buffer [ temp_index ] . timestamp ) )
zm_terminate = true ;
//frame_sent = true;
}
}
}
if ( temp_read_index = = temp_write_index )
{
// Go back to live viewing
Warning ( " Rewound over write index, resuming live play " ) ;
// Clear paused flag
paused = false ;
// Clear delayed_play flag
delayed = false ;
replay_rate = ZM_RATE_BASE ;
}
}
if ( ( unsigned int ) last_read_index ! = monitor - > shared_data - > last_write_index )
{
int index = monitor - > shared_data - > last_write_index % monitor - > image_buffer_count ;
last_read_index = monitor - > shared_data - > last_write_index ;
//Debug( 1, "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer );
if ( ( frame_mod = = 1 ) | | ( ( frame_count % frame_mod ) = = 0 ) )
{
if ( ! paused & & ! delayed )
{
// Send the next frame
Monitor : : Snapshot * snap = & monitor - > image_buffer [ index ] ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
if ( ! sendFrame ( snap - > image , snap - > timestamp ) )
zm_terminate = true ;
memcpy ( & last_frame_timestamp , snap - > timestamp , sizeof ( last_frame_timestamp ) ) ;
//frame_sent = true;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
temp_read_index = temp_write_index ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
if ( buffered_playback )
{
if ( monitor - > shared_data - > valid )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( monitor - > image_buffer [ index ] . timestamp - > tv_sec )
{
int temp_index = temp_write_index % temp_image_buffer_count ;
Debug ( 2 , " Storing frame %d " , temp_index ) ;
if ( ! temp_image_buffer [ temp_index ] . valid )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
snprintf ( temp_image_buffer [ temp_index ] . file_name , sizeof ( temp_image_buffer [ 0 ] . file_name ) , " %s/zmswap-i%05d.jpg " , swap_path , temp_index ) ;
temp_image_buffer [ temp_index ] . valid = true ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
memcpy ( & ( temp_image_buffer [ temp_index ] . timestamp ) , monitor - > image_buffer [ index ] . timestamp , sizeof ( temp_image_buffer [ 0 ] . timestamp ) ) ;
monitor - > image_buffer [ index ] . image - > WriteJpeg ( temp_image_buffer [ temp_index ] . file_name , config . jpeg_file_quality ) ;
temp_write_index = MOD_ADD ( temp_write_index , 1 , temp_image_buffer_count ) ;
if ( temp_write_index = = temp_read_index )
{
// Go back to live viewing
Warning ( " Exceeded temporary buffer, resuming live play " ) ;
// Clear paused flag
paused = false ;
// Clear delayed_play flag
delayed = false ;
replay_rate = ZM_RATE_BASE ;
}
}
else
{
Warning ( " Unable to store frame as timestamp invalid " ) ;
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
else
2009-05-08 17:47:37 +08:00
{
2016-04-04 22:11:48 +08:00
Warning ( " Unable to store frame as shared memory invalid " ) ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
}
frame_count + + ;
2009-05-08 17:47:37 +08:00
}
2016-04-04 22:11:48 +08:00
usleep ( ( unsigned long ) ( ( 1000000 * ZM_RATE_BASE ) / ( ( base_fps ? base_fps : 1 ) * abs ( replay_rate * 2 ) ) ) ) ;
if ( ttl )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( ( now . tv_sec - stream_start_time ) > ttl )
{
break ;
}
}
if ( ( TV_2_FLOAT ( now ) - last_frame_sent ) > max_secs_since_last_sent_frame )
{
Error ( " Terminating, last frame sent time %f secs more than maximum of %f " , TV_2_FLOAT ( now ) - last_frame_sent , max_secs_since_last_sent_frame ) ;
break ;
}
}
if ( buffered_playback )
{
char swap_path [ PATH_MAX ] = " " ;
2007-08-30 02:11:09 +08:00
2016-04-04 22:11:48 +08:00
snprintf ( swap_path , sizeof ( swap_path ) , " %s/zmswap-m%d/zmswap-q%06d " , config . path_swap , monitor - > Id ( ) , connkey ) ;
Debug ( 1 , " Cleaning swap files from %s " , swap_path ) ;
struct stat stat_buf ;
if ( stat ( swap_path , & stat_buf ) < 0 )
{
if ( errno ! = ENOENT )
{
Error ( " Can't stat '%s': %s " , swap_path , strerror ( errno ) ) ;
}
}
else if ( ! S_ISDIR ( stat_buf . st_mode ) )
{
Error ( " Swap image path '%s' is not a directory " , swap_path ) ;
}
else
{
char glob_pattern [ PATH_MAX ] = " " ;
snprintf ( glob_pattern , sizeof ( glob_pattern ) , " %s/*.* " , swap_path ) ;
glob_t pglob ;
int glob_status = glob ( glob_pattern , 0 , 0 , & pglob ) ;
if ( glob_status ! = 0 )
{
if ( glob_status < 0 )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
Error ( " Can't glob '%s': %s " , glob_pattern , strerror ( errno ) ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
else
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
Debug ( 1 , " Can't glob '%s': %d " , glob_pattern , glob_status ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
else
{
for ( unsigned int i = 0 ; i < pglob . gl_pathc ; i + + )
2007-08-30 02:11:09 +08:00
{
2016-04-04 22:11:48 +08:00
if ( unlink ( pglob . gl_pathv [ i ] ) < 0 )
{
Error ( " Can't unlink '%s': %s " , pglob . gl_pathv [ i ] , strerror ( errno ) ) ;
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
globfree ( & pglob ) ;
if ( rmdir ( swap_path ) < 0 )
{
Error ( " Can't rmdir '%s': %s " , swap_path , strerror ( errno ) ) ;
}
}
}
if ( swap_path ) free ( swap_path ) ;
closeComms ( ) ;
2007-08-30 02:11:09 +08:00
}
void Monitor : : SingleImage ( int scale )
{
2016-04-04 22:11:48 +08:00
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 ! = ZM_SCALE_BASE )
{
scaled_image . Assign ( * snap_image ) ;
scaled_image . Scale ( scale ) ;
snap_image = & scaled_image ;
}
if ( ! config . timestamp_on_capture )
{
TimestampImage ( snap_image , snap - > timestamp ) ;
}
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 ) ;
2007-08-30 02:11:09 +08:00
}
void Monitor : : SingleImageRaw ( int scale )
{
2016-04-04 22:11:48 +08:00
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 ! = ZM_SCALE_BASE )
{
scaled_image . Assign ( * snap_image ) ;
scaled_image . Scale ( scale ) ;
snap_image = & scaled_image ;
}
if ( ! config . timestamp_on_capture )
{
TimestampImage ( snap_image , snap - > timestamp ) ;
}
fprintf ( stdout , " Content-Length: %d \r \n " , snap_image - > Size ( ) ) ;
fprintf ( stdout , " Content-Type: image/x-rgb \r \n \r \n " ) ;
fwrite ( snap_image - > Buffer ( ) , snap_image - > Size ( ) , 1 , stdout ) ;
2007-08-30 02:11:09 +08:00
}
void Monitor : : SingleImageZip ( int scale )
{
2016-04-04 22:11:48 +08:00
unsigned long img_buffer_size = 0 ;
static Bytef 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 ! = ZM_SCALE_BASE )
{
scaled_image . Assign ( * snap_image ) ;
scaled_image . Scale ( scale ) ;
snap_image = & scaled_image ;
}
if ( ! config . timestamp_on_capture )
{
TimestampImage ( snap_image , snap - > timestamp ) ;
}
snap_image - > Zip ( img_buffer , & img_buffer_size ) ;
fprintf ( stdout , " Content-Length: %ld \r \n " , img_buffer_size ) ;
fprintf ( stdout , " Content-Type: image/x-rgbz \r \n \r \n " ) ;
fwrite ( img_buffer , img_buffer_size , 1 , stdout ) ;
2007-08-30 02:11:09 +08:00
}
2016-08-11 00:22:04 +08:00
unsigned int Monitor : : Colours ( ) const { return ( camera - > Colours ( ) ) ; }
unsigned int Monitor : : SubpixelOrder ( ) const { return ( camera - > SubpixelOrder ( ) ) ; }
int Monitor : : PrimeCapture ( ) {
return ( camera - > PrimeCapture ( ) ) ;
}
int Monitor : : PreCapture ( ) {
return ( camera - > PreCapture ( ) ) ;
}
int Monitor : : PostCapture ( ) {
return ( camera - > PostCapture ( ) ) ;
}
Monitor : : Orientation Monitor : : getOrientation ( ) const { return orientation ; }