diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 7d418abf9..f157c7ab7 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -29,104 +29,104 @@ int zmDbConnected = false; void zmDbConnect() { - if ( !mysql_init( &dbconn ) ) - { - Error( "Can't initialise database connection: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - my_bool reconnect = 1; - if ( mysql_options( &dbconn, MYSQL_OPT_RECONNECT, &reconnect ) ) - Fatal( "Can't set database auto reconnect option: %s", mysql_error( &dbconn ) ); - std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":/" ); - if ( colonIndex != std::string::npos ) + if ( !mysql_init( &dbconn ) ) + { + Error( "Can't initialise database connection: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + my_bool reconnect = 1; + if ( mysql_options( &dbconn, MYSQL_OPT_RECONNECT, &reconnect ) ) + Fatal( "Can't set database auto reconnect option: %s", mysql_error( &dbconn ) ); + std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":/" ); + if ( colonIndex != std::string::npos ) + { + std::string dbHost = staticConfig.DB_HOST.substr( 0, colonIndex ); + std::string dbPort = staticConfig.DB_HOST.substr( colonIndex+1 ); + if ( !mysql_real_connect( &dbconn, dbHost.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), 0, atoi(dbPort.c_str()), 0, 0 ) ) { - std::string dbHost = staticConfig.DB_HOST.substr( 0, colonIndex ); - std::string dbPort = staticConfig.DB_HOST.substr( colonIndex+1 ); - if ( !mysql_real_connect( &dbconn, dbHost.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), 0, atoi(dbPort.c_str()), 0, 0 ) ) - { - Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); } - else + } + else + { + if ( !mysql_real_connect( &dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), 0, 0, 0, 0 ) ) { - if ( !mysql_real_connect( &dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), 0, 0, 0, 0 ) ) - { - Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); } - if ( mysql_select_db( &dbconn, staticConfig.DB_NAME.c_str() ) ) - { - Error( "Can't select database: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - zmDbConnected = true; + } + if ( mysql_select_db( &dbconn, staticConfig.DB_NAME.c_str() ) ) + { + Error( "Can't select database: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + zmDbConnected = true; } void zmDbClose() { - if ( zmDbConnected ) - { - mysql_close( &dbconn ); - // mysql_init() call implicitly mysql_library_init() but - // mysql_close() does not call mysql_library_end() - mysql_library_end(); - zmDbConnected = false; - } + if ( zmDbConnected ) + { + mysql_close( &dbconn ); + // mysql_init() call implicitly mysql_library_init() but + // mysql_close() does not call mysql_library_end() + mysql_library_end(); + zmDbConnected = false; + } } MYSQL_RES * zmDbFetch( const char * query ) { - if ( ! zmDbConnected ) { - Error( "Not connected." ); - return NULL; - } + if ( ! zmDbConnected ) { + Error( "Not connected." ); + return NULL; + } - if ( mysql_query( &dbconn, query ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - return NULL; - } - Debug( 4, "Success running query: %s", query ); - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) { - Error( "Can't use query result: %s for query %s", mysql_error( &dbconn ), query ); - return NULL; - } - return result; + if ( mysql_query( &dbconn, query ) ) { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + return NULL; + } + Debug( 4, "Success running query: %s", query ); + MYSQL_RES *result = mysql_store_result( &dbconn ); + if ( !result ) { + Error( "Can't use query result: %s for query %s", mysql_error( &dbconn ), query ); + return NULL; + } + return result; } // end MYSQL_RES * zmDbFetch( const char * query ); zmDbRow *zmDbFetchOne( const char *query ) { - zmDbRow *row = new zmDbRow(); - if ( row->fetch( query ) ) { - return row; - } - delete row; - return NULL; + zmDbRow *row = new zmDbRow(); + if ( row->fetch( query ) ) { + return row; + } + delete row; + return NULL; } MYSQL_RES *zmDbRow::fetch( const char *query ) { - result_set = zmDbFetch( query ); - if ( ! result_set ) return result_set; + result_set = zmDbFetch( query ); + if ( ! result_set ) return result_set; - int n_rows = mysql_num_rows( result_set ); - if ( n_rows != 1 ) { - Error( "Bogus number of lines return from query, %d returned for query %s.", n_rows, query ); - mysql_free_result( result_set ); - result_set = NULL; - return result_set; - } - - row = mysql_fetch_row( result_set ); - if ( ! row ) { - mysql_free_result( result_set ); - result_set = NULL; - Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) ); - } else { - Debug(3, "Succes"); - } + int n_rows = mysql_num_rows( result_set ); + if ( n_rows != 1 ) { + Error( "Bogus number of lines return from query, %d returned for query %s.", n_rows, query ); + mysql_free_result( result_set ); + result_set = NULL; return result_set; + } + + row = mysql_fetch_row( result_set ); + if ( ! row ) { + mysql_free_result( result_set ); + result_set = NULL; + Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) ); + } else { + Debug(3, "Succes"); + } + return result_set; } zmDbRow::~zmDbRow() { - if ( result_set ) - mysql_free_result( result_set ); + if ( result_set ) + mysql_free_result( result_set ); } diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 58c99ed37..50baea77e 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -60,1575 +60,1575 @@ int Event::pre_alarm_count = 0; Event::PreAlarmData Event::pre_alarm_data[MAX_PRE_ALARM_FRAMES] = { { 0 } }; Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent ) : - monitor( p_monitor ), - start_time( p_start_time ), - cause( p_cause ), - noteSetMap( p_noteSetMap ), - videoEvent( p_videoEvent ), - videowriter( NULL ) + monitor( p_monitor ), + start_time( p_start_time ), + cause( p_cause ), + noteSetMap( p_noteSetMap ), + videoEvent( p_videoEvent ), + videowriter( NULL ) { - if ( !initialised ) - Initialise(); + if ( !initialised ) + Initialise(); - std::string notes; - createNotes( notes ); + std::string notes; + createNotes( notes ); - bool untimedEvent = false; - if ( !start_time.tv_sec ) + bool untimedEvent = false; + if ( !start_time.tv_sec ) + { + untimedEvent = true; + gettimeofday( &start_time, 0 ); + } + + Storage * storage = monitor->getStorage(); + + static char sql[ZM_SQL_MED_BUFSIZ]; + + struct tm *stime = localtime( &start_time.tv_sec ); + snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, Videoed ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d )", monitor->Id(), storage->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str(), videoEvent ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql ); + exit( mysql_errno( &dbconn ) ); + } + id = mysql_insert_id( &dbconn ); + if ( untimedEvent ) + { + Warning( "Event %d has zero time, setting to current", id ); + } + end_time.tv_sec = 0; + frames = 0; + alarm_frames = 0; + tot_score = 0; + max_score = 0; + + if ( config.use_deep_storage ) + { + char *path_ptr = path; + path_ptr += snprintf( path_ptr, sizeof(path), "%s/%d", storage->Path(), monitor->Id() ); + + int dt_parts[6]; + dt_parts[0] = stime->tm_year-100; + dt_parts[1] = stime->tm_mon+1; + dt_parts[2] = stime->tm_mday; + dt_parts[3] = stime->tm_hour; + dt_parts[4] = stime->tm_min; + dt_parts[5] = stime->tm_sec; + + char date_path[PATH_MAX] = ""; + char time_path[PATH_MAX] = ""; + char *time_path_ptr = time_path; + for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) { - untimedEvent = true; - gettimeofday( &start_time, 0 ); - } + path_ptr += snprintf( path_ptr, sizeof(path)-(path_ptr-path), "/%02d", dt_parts[i] ); - Storage * storage = monitor->getStorage(); - - static char sql[ZM_SQL_MED_BUFSIZ]; - - struct tm *stime = localtime( &start_time.tv_sec ); - snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, Videoed ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d )", monitor->Id(), storage->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str(), videoEvent ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql ); - exit( mysql_errno( &dbconn ) ); - } - id = mysql_insert_id( &dbconn ); - if ( untimedEvent ) - { - Warning( "Event %d has zero time, setting to current", id ); - } - end_time.tv_sec = 0; - frames = 0; - alarm_frames = 0; - tot_score = 0; - max_score = 0; - - if ( config.use_deep_storage ) - { - char *path_ptr = path; - path_ptr += snprintf( path_ptr, sizeof(path), "%s/%d", storage->Path(), monitor->Id() ); - - int dt_parts[6]; - dt_parts[0] = stime->tm_year-100; - dt_parts[1] = stime->tm_mon+1; - dt_parts[2] = stime->tm_mday; - dt_parts[3] = stime->tm_hour; - dt_parts[4] = stime->tm_min; - dt_parts[5] = stime->tm_sec; - - char date_path[PATH_MAX] = ""; - char time_path[PATH_MAX] = ""; - char *time_path_ptr = time_path; - for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) - { - path_ptr += snprintf( path_ptr, sizeof(path)-(path_ptr-path), "/%02d", dt_parts[i] ); - - struct stat statbuf; - errno = 0; - if ( stat( path, &statbuf ) ) { - if ( errno == ENOENT || errno == ENOTDIR ) - { - if ( mkdir( path, 0755 ) ) - { - Fatal( "Can't mkdir %s: %s", path, strerror(errno)); - } - } else { - Warning( "Error stat'ing %s, may be fatal. error is %s", path, strerror(errno)); - } - } - if ( i == 2 ) - strncpy( date_path, path, sizeof(date_path) ); - else if ( i >= 3 ) - time_path_ptr += snprintf( time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i] ); - } - char id_file[PATH_MAX]; - // Create event id symlink - snprintf( id_file, sizeof(id_file), "%s/.%d", date_path, id ); - if ( symlink( time_path, id_file ) < 0 ) - Fatal( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno)); - // Create empty id tag file - snprintf( id_file, sizeof(id_file), "%s/.%d", path, id ); - if ( FILE *id_fp = fopen( id_file, "w" ) ) - fclose( id_fp ); - else - Fatal( "Can't fopen %s: %s", id_file, strerror(errno)); - } - else - { - snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id ); - - struct stat statbuf; - errno = 0; - stat( path, &statbuf ); + struct stat statbuf; + errno = 0; + if ( stat( path, &statbuf ) ) { if ( errno == ENOENT || errno == ENOTDIR ) { - if ( mkdir( path, 0755 ) ) - { - Error( "Can't mkdir %s: %s", path, strerror(errno)); - } + if ( mkdir( path, 0755 ) ) + { + Fatal( "Can't mkdir %s: %s", path, strerror(errno)); + } + } else { + Warning( "Error stat'ing %s, may be fatal. error is %s", path, strerror(errno)); } - char id_file[PATH_MAX]; - // Create empty id tag file - snprintf( id_file, sizeof(id_file), "%s/.%d", path, id ); - if ( FILE *id_fp = fopen( id_file, "w" ) ) - fclose( id_fp ); - else - Fatal( "Can't fopen %s: %s", id_file, strerror(errno)); + } + if ( i == 2 ) + strncpy( date_path, path, sizeof(date_path) ); + else if ( i >= 3 ) + time_path_ptr += snprintf( time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i] ); } - last_db_frame = 0; + char id_file[PATH_MAX]; + // Create event id symlink + snprintf( id_file, sizeof(id_file), "%s/.%d", date_path, id ); + if ( symlink( time_path, id_file ) < 0 ) + Fatal( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno)); + // Create empty id tag file + snprintf( id_file, sizeof(id_file), "%s/.%d", path, id ); + if ( FILE *id_fp = fopen( id_file, "w" ) ) + fclose( id_fp ); + else + Fatal( "Can't fopen %s: %s", id_file, strerror(errno)); + } + else + { + snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id ); - video_name[0] = 0; + struct stat statbuf; + errno = 0; + stat( path, &statbuf ); + if ( errno == ENOENT || errno == ENOTDIR ) + { + if ( mkdir( path, 0755 ) ) + { + Error( "Can't mkdir %s: %s", path, strerror(errno)); + } + } + char id_file[PATH_MAX]; + // Create empty id tag file + snprintf( id_file, sizeof(id_file), "%s/.%d", path, id ); + if ( FILE *id_fp = fopen( id_file, "w" ) ) + fclose( id_fp ); + else + Fatal( "Can't fopen %s: %s", id_file, strerror(errno)); + } + last_db_frame = 0; - /* Save as video */ + video_name[0] = 0; - if ( monitor->GetOptVideoWriter() != 0 ) { - int nRet; - snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); - snprintf( video_file, sizeof(video_file), video_file_format, path, video_name ); - snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" ); - snprintf( timecodes_file, sizeof(timecodes_file), video_file_format, path, timecodes_name ); + /* Save as video */ + + if ( monitor->GetOptVideoWriter() != 0 ) { + int nRet; + snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); + snprintf( video_file, sizeof(video_file), video_file_format, path, video_name ); + snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" ); + snprintf( timecodes_file, sizeof(timecodes_file), video_file_format, path, timecodes_name ); - /* X264 MP4 video writer */ - if(monitor->GetOptVideoWriter() == 1) { + /* X264 MP4 video writer */ + if(monitor->GetOptVideoWriter() == 1) { #if ZM_HAVE_VIDEOWRITER_X264MP4 - videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams()); + videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams()); #else - videowriter = NULL; - Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)"); + videowriter = NULL; + Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)"); #endif - } + } - if(videowriter != NULL) { - /* Open the video stream */ - nRet = videowriter->Open(); - if(nRet != 0) { - Error("Failed opening video stream"); - delete videowriter; - videowriter = NULL; - } + if(videowriter != NULL) { + /* Open the video stream */ + nRet = videowriter->Open(); + if(nRet != 0) { + Error("Failed opening video stream"); + delete videowriter; + videowriter = NULL; + } - /* Create timecodes file */ - timecodes_fd = fopen(timecodes_file, "wb"); - if(timecodes_fd == NULL) { - Error("Failed creating timecodes file"); - } - } - } else { - /* No video object */ - videowriter = NULL; - } + /* Create timecodes file */ + timecodes_fd = fopen(timecodes_file, "wb"); + if(timecodes_fd == NULL) { + Error("Failed creating timecodes file"); + } + } + } else { + /* No video object */ + videowriter = NULL; + } } Event::~Event() { - if ( frames > last_db_frame ) - { - struct DeltaTimeval delta_time; - DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 ); - - Debug( 1, "Adding closing frame %d to DB", frames ); - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't insert frame: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - } - - /* Close the video file */ - if ( videowriter != NULL ) { - int nRet; - - nRet = videowriter->Close(); - if(nRet != 0) { - Error("Failed closing video stream"); - } - delete videowriter; - videowriter = NULL; - - /* Close the timecodes file */ - fclose(timecodes_fd); - timecodes_fd = NULL; - } - - static char sql[ZM_SQL_MED_BUFSIZ]; - + if ( frames > last_db_frame ) + { struct DeltaTimeval delta_time; DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 ); - snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); + Debug( 1, "Adding closing frame %d to DB", frames ); + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't update event: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + Error( "Can't insert frame: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); } + } + + /* Close the video file */ + if ( videowriter != NULL ) { + int nRet; + + nRet = videowriter->Close(); + if(nRet != 0) { + Error("Failed closing video stream"); + } + delete videowriter; + videowriter = NULL; + + /* Close the timecodes file */ + fclose(timecodes_fd); + timecodes_fd = NULL; + } + + static char sql[ZM_SQL_MED_BUFSIZ]; + + struct DeltaTimeval delta_time; + DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 ); + + snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't update event: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } } void Event::createNotes( std::string ¬es ) { - notes.clear(); - for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); mapIter++ ) + notes.clear(); + for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); mapIter++ ) + { + notes += mapIter->first; + notes += ": "; + const StringSet &stringSet = mapIter->second; + for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); setIter++ ) { - notes += mapIter->first; - notes += ": "; - const StringSet &stringSet = mapIter->second; - for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); setIter++ ) - { - if ( setIter != stringSet.begin() ) - notes += ", "; - notes += *setIter; - } + if ( setIter != stringSet.begin() ) + notes += ", "; + notes += *setIter; } + } } int Event::sd = -1; bool Event::OpenFrameSocket( int monitor_id ) { - if ( sd > 0 ) + if ( sd > 0 ) + { + close( sd ); + } + + sd = socket( AF_UNIX, SOCK_STREAM, 0); + if ( sd < 0 ) + { + Error( "Can't create socket: %s", strerror(errno) ); + return( false ); + } + + int socket_buffer_size = config.frame_socket_size; + if ( socket_buffer_size > 0 ) + { + if ( setsockopt( sd, SOL_SOCKET, SO_SNDBUF, &socket_buffer_size, sizeof(socket_buffer_size) ) < 0 ) { - close( sd ); + Error( "Can't get socket buffer size to %d, error = %s", socket_buffer_size, strerror(errno) ); + close( sd ); + sd = -1; + return( false ); } + } - sd = socket( AF_UNIX, SOCK_STREAM, 0); - if ( sd < 0 ) - { - Error( "Can't create socket: %s", strerror(errno) ); - return( false ); - } + int flags; + if ( (flags = fcntl( sd, F_GETFL )) < 0 ) + { + Error( "Can't get socket flags, error = %s", strerror(errno) ); + close( sd ); + sd = -1; + return( false ); + } + flags |= O_NONBLOCK; + if ( fcntl( sd, F_SETFL, flags ) < 0 ) + { + Error( "Can't set socket flags, error = %s", strerror(errno) ); + close( sd ); + sd = -1; + return( false ); + } - int socket_buffer_size = config.frame_socket_size; - if ( socket_buffer_size > 0 ) - { - if ( setsockopt( sd, SOL_SOCKET, SO_SNDBUF, &socket_buffer_size, sizeof(socket_buffer_size) ) < 0 ) - { - Error( "Can't get socket buffer size to %d, error = %s", socket_buffer_size, strerror(errno) ); - close( sd ); - sd = -1; - return( false ); - } - } + char sock_path[PATH_MAX] = ""; + snprintf( sock_path, sizeof(sock_path), "%s/zmf-%d.sock", config.path_socks, monitor_id ); - int flags; - if ( (flags = fcntl( sd, F_GETFL )) < 0 ) - { - Error( "Can't get socket flags, error = %s", strerror(errno) ); - close( sd ); - sd = -1; - return( false ); - } - flags |= O_NONBLOCK; - if ( fcntl( sd, F_SETFL, flags ) < 0 ) - { - Error( "Can't set socket flags, error = %s", strerror(errno) ); - close( sd ); - sd = -1; - return( false ); - } + struct sockaddr_un addr; - char sock_path[PATH_MAX] = ""; - snprintf( sock_path, sizeof(sock_path), "%s/zmf-%d.sock", config.path_socks, monitor_id ); + strncpy( addr.sun_path, sock_path, sizeof(addr.sun_path) ); + addr.sun_family = AF_UNIX; - struct sockaddr_un addr; + if ( connect( sd, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)) < 0 ) + { + Warning( "Can't connect to frame server: %s", strerror(errno) ); + close( sd ); + sd = -1; + return( false ); + } - strncpy( addr.sun_path, sock_path, sizeof(addr.sun_path) ); - addr.sun_family = AF_UNIX; - - if ( connect( sd, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)) < 0 ) - { - Warning( "Can't connect to frame server: %s", strerror(errno) ); - close( sd ); - sd = -1; - return( false ); - } - - Debug( 1, "Opened connection to frame server" ); - return( true ); + Debug( 1, "Opened connection to frame server" ); + return( true ); } bool Event::ValidateFrameSocket( int monitor_id ) { - if ( sd < 0 ) - { - return( OpenFrameSocket( monitor_id ) ); - } - return( true ); + if ( sd < 0 ) + { + return( OpenFrameSocket( monitor_id ) ); + } + return( true ); } bool Event::SendFrameImage( const Image *image, bool alarm_frame ) { - if ( !ValidateFrameSocket( monitor->Id() ) ) + if ( !ValidateFrameSocket( monitor->Id() ) ) + { + return( false ); + } + + static int jpg_buffer_size = 0; + static unsigned char jpg_buffer[ZM_MAX_IMAGE_SIZE]; + + image->EncodeJpeg( jpg_buffer, &jpg_buffer_size, (alarm_frame&&(config.jpeg_alarm_file_quality>config.jpeg_file_quality))?config.jpeg_alarm_file_quality:config.jpeg_file_quality ); + + static FrameHeader frame_header; + + frame_header.event_id = id; + if ( config.use_deep_storage ) + frame_header.event_time = start_time.tv_sec; + frame_header.frame_id = frames; + frame_header.alarm_frame = alarm_frame; + frame_header.image_length = jpg_buffer_size; + + struct iovec iovecs[2]; + iovecs[0].iov_base = &frame_header; + iovecs[0].iov_len = sizeof(frame_header); + iovecs[1].iov_base = jpg_buffer; + iovecs[1].iov_len = jpg_buffer_size; + + ssize_t writev_size = sizeof(frame_header)+jpg_buffer_size; + ssize_t writev_result = writev( sd, iovecs, sizeof(iovecs)/sizeof(*iovecs)); + if ( writev_result != writev_size ) + { + if ( writev_result < 0 ) { - return( false ); + if ( errno == EAGAIN ) + { + Warning( "Blocking write detected" ); + } + else + { + Error( "Can't write frame: %s", strerror(errno) ); + close( sd ); + sd = -1; + } } - - static int jpg_buffer_size = 0; - static unsigned char jpg_buffer[ZM_MAX_IMAGE_SIZE]; - - image->EncodeJpeg( jpg_buffer, &jpg_buffer_size, (alarm_frame&&(config.jpeg_alarm_file_quality>config.jpeg_file_quality))?config.jpeg_alarm_file_quality:config.jpeg_file_quality ); - - static FrameHeader frame_header; - - frame_header.event_id = id; - if ( config.use_deep_storage ) - frame_header.event_time = start_time.tv_sec; - frame_header.frame_id = frames; - frame_header.alarm_frame = alarm_frame; - frame_header.image_length = jpg_buffer_size; - - struct iovec iovecs[2]; - iovecs[0].iov_base = &frame_header; - iovecs[0].iov_len = sizeof(frame_header); - iovecs[1].iov_base = jpg_buffer; - iovecs[1].iov_len = jpg_buffer_size; - - ssize_t writev_size = sizeof(frame_header)+jpg_buffer_size; - ssize_t writev_result = writev( sd, iovecs, sizeof(iovecs)/sizeof(*iovecs)); - if ( writev_result != writev_size ) + else { - if ( writev_result < 0 ) - { - if ( errno == EAGAIN ) - { - Warning( "Blocking write detected" ); - } - else - { - Error( "Can't write frame: %s", strerror(errno) ); - close( sd ); - sd = -1; - } - } - else - { - Error( "Incomplete frame write: %zd of %zd bytes written", writev_result, writev_size ); - close( sd ); - sd = -1; - } - return( false ); + Error( "Incomplete frame write: %zd of %zd bytes written", writev_result, writev_size ); + close( sd ); + sd = -1; } - Debug( 1, "Wrote frame image, %d bytes", jpg_buffer_size ); + return( false ); + } + Debug( 1, "Wrote frame image, %d bytes", jpg_buffer_size ); - return( true ); + return( true ); } bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame ) { - Image* ImgToWrite; - Image* ts_image = NULL; + Image* ImgToWrite; + Image* ts_image = NULL; - if ( config.timestamp_on_capture ) // stash the image we plan to use in another pointer regardless if timestamped. - { - ts_image = new Image(*image); - monitor->TimestampImage( ts_image, ×tamp ); - ImgToWrite=ts_image; - } - else - ImgToWrite=image; + if ( config.timestamp_on_capture ) // stash the image we plan to use in another pointer regardless if timestamped. + { + ts_image = new Image(*image); + monitor->TimestampImage( ts_image, ×tamp ); + ImgToWrite=ts_image; + } + else + ImgToWrite=image; - if ( !config.opt_frame_server || !SendFrameImage(ImgToWrite, alarm_frame) ) - { - int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default - ImgToWrite->WriteJpeg( event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0}) ); // exif is only timestamp at present this switches on or off for write - } - if(ts_image) delete(ts_image); // clean up if used. - return( true ); + if ( !config.opt_frame_server || !SendFrameImage(ImgToWrite, alarm_frame) ) + { + int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default + ImgToWrite->WriteJpeg( event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0}) ); // exif is only timestamp at present this switches on or off for write + } + if(ts_image) delete(ts_image); // clean up if used. + return( true ); } bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ) { - const Image* frameimg = image; - Image ts_image; + const Image* frameimg = image; + Image ts_image; - /* Checking for invalid parameters */ - if ( videow == NULL ) { - Error("NULL Video object"); - return false; - } + /* Checking for invalid parameters */ + if ( videow == NULL ) { + Error("NULL Video object"); + return false; + } - /* If the image does not contain a timestamp, add the timestamp */ - if (!config.timestamp_on_capture) { - ts_image = *image; - monitor->TimestampImage( &ts_image, ×tamp ); - frameimg = &ts_image; - } + /* If the image does not contain a timestamp, add the timestamp */ + if (!config.timestamp_on_capture) { + ts_image = *image; + monitor->TimestampImage( &ts_image, ×tamp ); + frameimg = &ts_image; + } - /* Calculate delta time */ - struct DeltaTimeval delta_time3; - DELTA_TIMEVAL( delta_time3, timestamp, start_time, DT_PREC_3 ); - unsigned int timeMS = (delta_time3.sec * delta_time3.prec) + delta_time3.fsec; + /* Calculate delta time */ + struct DeltaTimeval delta_time3; + DELTA_TIMEVAL( delta_time3, timestamp, start_time, DT_PREC_3 ); + unsigned int timeMS = (delta_time3.sec * delta_time3.prec) + delta_time3.fsec; - /* Encode and write the frame */ - if(videowriter->Encode(frameimg, timeMS) != 0) { - Error("Failed encoding video frame"); - } + /* Encode and write the frame */ + if(videowriter->Encode(frameimg, timeMS) != 0) { + Error("Failed encoding video frame"); + } - /* Add the frame to the timecodes file */ - fprintf(timecodes_fd, "%u\n", timeMS); + /* Add the frame to the timecodes file */ + fprintf(timecodes_fd, "%u\n", timeMS); - return( true ); + return( true ); } void Event::updateNotes( const StringSetMap &newNoteSetMap ) { - bool update = false; + bool update = false; - //Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() ); - if ( newNoteSetMap.size() > 0 ) + //Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() ); + if ( newNoteSetMap.size() > 0 ) + { + if ( noteSetMap.size() == 0 ) { - if ( noteSetMap.size() == 0 ) + noteSetMap = newNoteSetMap; + update = true; + } + else + { + for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); newNoteSetMapIter++ ) + { + const std::string &newNoteGroup = newNoteSetMapIter->first; + const StringSet &newNoteSet = newNoteSetMapIter->second; + //Info( "Got %d new strings", newNoteSet.size() ); + if ( newNoteSet.size() > 0 ) { - noteSetMap = newNoteSetMap; + StringSetMap::iterator noteSetMapIter = noteSetMap.find( newNoteGroup ); + if ( noteSetMapIter == noteSetMap.end() ) + { + //Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() ); + noteSetMap.insert( StringSetMap::value_type( newNoteGroup, newNoteSet ) ); update = true; - } - else - { - for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); newNoteSetMapIter++ ) + } + else + { + StringSet ¬eSet = noteSetMapIter->second; + //Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() ); + for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); newNoteSetIter++ ) { - const std::string &newNoteGroup = newNoteSetMapIter->first; - const StringSet &newNoteSet = newNoteSetMapIter->second; - //Info( "Got %d new strings", newNoteSet.size() ); - if ( newNoteSet.size() > 0 ) - { - StringSetMap::iterator noteSetMapIter = noteSetMap.find( newNoteGroup ); - if ( noteSetMapIter == noteSetMap.end() ) - { - //Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() ); - noteSetMap.insert( StringSetMap::value_type( newNoteGroup, newNoteSet ) ); - update = true; - } - else - { - StringSet ¬eSet = noteSetMapIter->second; - //Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() ); - for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); newNoteSetIter++ ) - { - const std::string &newNote = *newNoteSetIter; - StringSet::iterator noteSetIter = noteSet.find( newNote ); - if ( noteSetIter == noteSet.end() ) - { - noteSet.insert( newNote ); - update = true; - } - } - } - } + const std::string &newNote = *newNoteSetIter; + StringSet::iterator noteSetIter = noteSet.find( newNote ); + if ( noteSetIter == noteSet.end() ) + { + noteSet.insert( newNote ); + update = true; + } } + } } + } } + } - if ( update ) - { - std::string notes; - createNotes( notes ); + if ( update ) + { + std::string notes; + createNotes( notes ); - Debug( 2, "Updating notes for event %d, '%s'", id, notes.c_str() ); - static char sql[ZM_SQL_MED_BUFSIZ]; + Debug( 2, "Updating notes for event %d, '%s'", id, notes.c_str() ); + static char sql[ZM_SQL_MED_BUFSIZ]; #if USE_PREPARED_SQL - static MYSQL_STMT *stmt = 0; + static MYSQL_STMT *stmt = 0; - char notesStr[ZM_SQL_MED_BUFSIZ] = ""; - unsigned long notesLen = 0; + char notesStr[ZM_SQL_MED_BUFSIZ] = ""; + unsigned long notesLen = 0; - if ( !stmt ) - { - const char *sql = "update Events set Notes = ? where Id = ?"; + if ( !stmt ) + { + const char *sql = "update Events set Notes = ? where Id = ?"; - stmt = mysql_stmt_init( &dbconn ); - if ( mysql_stmt_prepare( stmt, sql, strlen(sql) ) ) - { - Fatal( "Unable to prepare sql '%s': %s", sql, mysql_stmt_error(stmt) ); - } + stmt = mysql_stmt_init( &dbconn ); + if ( mysql_stmt_prepare( stmt, sql, strlen(sql) ) ) + { + Fatal( "Unable to prepare sql '%s': %s", sql, mysql_stmt_error(stmt) ); + } - /* Get the parameter count from the statement */ - if ( mysql_stmt_param_count( stmt ) != 2 ) - { - Fatal( "Unexpected parameter count %ld in sql '%s'", mysql_stmt_param_count( stmt ), sql ); - } + /* Get the parameter count from the statement */ + if ( mysql_stmt_param_count( stmt ) != 2 ) + { + Fatal( "Unexpected parameter count %ld in sql '%s'", mysql_stmt_param_count( stmt ), sql ); + } - MYSQL_BIND bind[2]; - memset(bind, 0, sizeof(bind)); + MYSQL_BIND bind[2]; + memset(bind, 0, sizeof(bind)); - /* STRING PARAM */ - bind[0].buffer_type = MYSQL_TYPE_STRING; - bind[0].buffer = (char *)notesStr; - bind[0].buffer_length = sizeof(notesStr); - bind[0].is_null = 0; - bind[0].length = ¬esLen; + /* STRING PARAM */ + bind[0].buffer_type = MYSQL_TYPE_STRING; + bind[0].buffer = (char *)notesStr; + bind[0].buffer_length = sizeof(notesStr); + bind[0].is_null = 0; + bind[0].length = ¬esLen; - bind[1].buffer_type= MYSQL_TYPE_LONG; - bind[1].buffer= (char *)&id; - bind[1].is_null= 0; - bind[1].length= 0; + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= (char *)&id; + bind[1].is_null= 0; + bind[1].length= 0; - /* Bind the buffers */ - if ( mysql_stmt_bind_param( stmt, bind ) ) - { - Fatal( "Unable to bind sql '%s': %s", sql, mysql_stmt_error(stmt) ); - } - } - - strncpy( notesStr, notes.c_str(), sizeof(notesStr) ); - notesLen = notes.length(); - - if ( mysql_stmt_execute( stmt ) ) - { - Fatal( "Unable to execute sql '%s': %s", sql, mysql_stmt_error(stmt) ); - } -#else - static char escapedNotes[ZM_SQL_MED_BUFSIZ]; - - mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() ); - - snprintf( sql, sizeof(sql), "update Events set Notes = '%s' where Id = %d", escapedNotes, id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't insert event: %s", mysql_error( &dbconn ) ); - } -#endif + /* Bind the buffers */ + if ( mysql_stmt_bind_param( stmt, bind ) ) + { + Fatal( "Unable to bind sql '%s': %s", sql, mysql_stmt_error(stmt) ); + } } + + strncpy( notesStr, notes.c_str(), sizeof(notesStr) ); + notesLen = notes.length(); + + if ( mysql_stmt_execute( stmt ) ) + { + Fatal( "Unable to execute sql '%s': %s", sql, mysql_stmt_error(stmt) ); + } +#else + static char escapedNotes[ZM_SQL_MED_BUFSIZ]; + + mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() ); + + snprintf( sql, sizeof(sql), "update Events set Notes = '%s' where Id = %d", escapedNotes, id ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't insert event: %s", mysql_error( &dbconn ) ); + } +#endif + } } void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps ) { - for (int i = 0; i < n_frames; i += ZM_SQL_BATCH_SIZE) { - AddFramesInternal(n_frames, i, images, timestamps); - } + for (int i = 0; i < n_frames; i += ZM_SQL_BATCH_SIZE) { + AddFramesInternal(n_frames, i, images, timestamps); + } } void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ) { - static char sql[ZM_SQL_LGE_BUFSIZ]; - strncpy( sql, "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ", sizeof(sql) ); - int frameCount = 0; - for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) + static char sql[ZM_SQL_LGE_BUFSIZ]; + strncpy( sql, "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ", sizeof(sql) ); + int frameCount = 0; + for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) + { + if ( !timestamps[i]->tv_sec ) { - if ( !timestamps[i]->tv_sec ) - { - Debug( 1, "Not adding pre-capture frame %d, zero timestamp", i ); - continue; - } - - frames++; - - static char event_file[PATH_MAX]; - snprintf( event_file, sizeof(event_file), capture_file_format, path, frames ); - if ( monitor->GetOptSaveJPEGs() & 4) { - //If this is the first frame, we should add a thumbnail to the event directory - if(frames == 10){ - char snapshot_file[PATH_MAX]; - snprintf( snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path ); - WriteFrameImage( images[i], *(timestamps[i]), snapshot_file ); - } - } - if ( monitor->GetOptSaveJPEGs() & 1) { - Debug( 1, "Writing pre-capture frame %d", frames ); - WriteFrameImage( images[i], *(timestamps[i]), event_file ); - } - if ( videowriter != NULL ) { - WriteFrameVideo( images[i], *(timestamps[i]), videowriter ); - } - - struct DeltaTimeval delta_time; - DELTA_TIMEVAL( delta_time, *(timestamps[i]), start_time, DT_PREC_2 ); - - int sql_len = strlen(sql); - snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %d, %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); - - frameCount++; - } - - if ( frameCount ) - { - Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames ); - *(sql+strlen(sql)-2) = '\0'; - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't insert frames: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - last_db_frame = frames; - } - else - { - Debug( 1, "No valid pre-capture frames to add" ); - } -} - -void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *alarm_image ) -{ - if ( !timestamp.tv_sec ) - { - Debug( 1, "Not adding new frame, zero timestamp" ); - return; + Debug( 1, "Not adding pre-capture frame %d, zero timestamp", i ); + continue; } frames++; static char event_file[PATH_MAX]; snprintf( event_file, sizeof(event_file), capture_file_format, path, frames ); - if ( monitor->GetOptSaveJPEGs() & 4) { - //If this is the first frame, we should add a thumbnail to the event directory - if(frames == 10){ - char snapshot_file[PATH_MAX]; - snprintf( snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path ); - WriteFrameImage( image, timestamp, snapshot_file ); - } + //If this is the first frame, we should add a thumbnail to the event directory + if(frames == 10){ + char snapshot_file[PATH_MAX]; + snprintf( snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path ); + WriteFrameImage( images[i], *(timestamps[i]), snapshot_file ); + } } - if( monitor->GetOptSaveJPEGs() & 1) { - Debug( 1, "Writing capture frame %d", frames ); - WriteFrameImage( image, timestamp, event_file ); + if ( monitor->GetOptSaveJPEGs() & 1) { + Debug( 1, "Writing pre-capture frame %d", frames ); + WriteFrameImage( images[i], *(timestamps[i]), event_file ); } if ( videowriter != NULL ) { - WriteFrameVideo( image, timestamp, videowriter ); + WriteFrameVideo( images[i], *(timestamps[i]), videowriter ); } struct DeltaTimeval delta_time; - DELTA_TIMEVAL( delta_time, timestamp, start_time, DT_PREC_2 ); + DELTA_TIMEVAL( delta_time, *(timestamps[i]), start_time, DT_PREC_2 ); - const char *frame_type = score>0?"Alarm":(score<0?"Bulk":"Normal"); - if ( score < 0 ) - score = 0; + int sql_len = strlen(sql); + snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %d, %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); - bool db_frame = (strcmp(frame_type,"Bulk") != 0) || ((frames%config.bulk_frame_interval)==0) || !frames; - if ( db_frame ) + frameCount++; + } + + if ( frameCount ) + { + Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames ); + *(sql+strlen(sql)-2) = '\0'; + if ( mysql_query( &dbconn, sql ) ) { - - Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, frame_type ); - static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %d, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type, timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't insert frame: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - last_db_frame = frames; - - // We are writing a Bulk frame - if ( !strcmp( frame_type,"Bulk") ) - { - snprintf( sql, sizeof(sql), "update Events set Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't update event: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - } + Error( "Can't insert frames: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); } + last_db_frame = frames; + } + else + { + Debug( 1, "No valid pre-capture frames to add" ); + } +} - end_time = timestamp; +void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *alarm_image ) +{ + if ( !timestamp.tv_sec ) + { + Debug( 1, "Not adding new frame, zero timestamp" ); + return; + } - // We are writing an Alarm frame - if ( !strcmp( frame_type,"Alarm") ) + frames++; + + static char event_file[PATH_MAX]; + snprintf( event_file, sizeof(event_file), capture_file_format, path, frames ); + + if ( monitor->GetOptSaveJPEGs() & 4) { + //If this is the first frame, we should add a thumbnail to the event directory + if(frames == 10){ + char snapshot_file[PATH_MAX]; + snprintf( snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path ); + WriteFrameImage( image, timestamp, snapshot_file ); + } + } + if( monitor->GetOptSaveJPEGs() & 1) { + Debug( 1, "Writing capture frame %d", frames ); + WriteFrameImage( image, timestamp, event_file ); + } + if ( videowriter != NULL ) { + WriteFrameVideo( image, timestamp, videowriter ); + } + + struct DeltaTimeval delta_time; + DELTA_TIMEVAL( delta_time, timestamp, start_time, DT_PREC_2 ); + + const char *frame_type = score>0?"Alarm":(score<0?"Bulk":"Normal"); + if ( score < 0 ) + score = 0; + + bool db_frame = (strcmp(frame_type,"Bulk") != 0) || ((frames%config.bulk_frame_interval)==0) || !frames; + if ( db_frame ) + { + + Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, frame_type ); + static char sql[ZM_SQL_MED_BUFSIZ]; + snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %d, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type, timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score ); + if ( mysql_query( &dbconn, sql ) ) { - alarm_frames++; - - tot_score += score; - if ( score > (int)max_score ) - max_score = score; - - if ( alarm_image ) - { - snprintf( event_file, sizeof(event_file), analyse_file_format, path, frames ); - - Debug( 1, "Writing analysis frame %d", frames ); - if ( monitor->GetOptSaveJPEGs() & 2) { - WriteFrameImage( alarm_image, timestamp, event_file, true ); - } - } + Error( "Can't insert frame: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); } - - /* This makes viewing the diagnostic images impossible because it keeps deleting them - if ( config.record_diag_images ) + last_db_frame = frames; + + // We are writing a Bulk frame + if ( !strcmp( frame_type,"Bulk") ) { - char diag_glob[PATH_MAX] = ""; - - snprintf( diag_glob, sizeof(diag_glob), "%s/%d/diag-*.jpg", config.dir_events, monitor->Id() ); - glob_t pglob; - int glob_status = glob( diag_glob, 0, 0, &pglob ); - if ( glob_status != 0 ) - { - if ( glob_status < 0 ) - { - Error( "Can't glob '%s': %s", diag_glob, strerror(errno) ); - } - else - { - Debug( 1, "Can't glob '%s': %d", diag_glob, glob_status ); - } - } - else - { - char new_diag_path[PATH_MAX] = ""; - for ( int i = 0; i < pglob.gl_pathc; i++ ) - { - char *diag_path = pglob.gl_pathv[i]; - - char *diag_file = strstr( diag_path, "diag-" ); - - if ( diag_file ) - { - snprintf( new_diag_path, sizeof(new_diag_path), general_file_format, path, frames, diag_file ); - - if ( rename( diag_path, new_diag_path ) < 0 ) - { - Error( "Can't rename '%s' to '%s': %s", diag_path, new_diag_path, strerror(errno) ); - } - } - } - } - globfree( &pglob ); + snprintf( sql, sizeof(sql), "update Events set Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, id ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't update event: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } } - */ + } + + end_time = timestamp; + + // We are writing an Alarm frame + if ( !strcmp( frame_type,"Alarm") ) + { + alarm_frames++; + + tot_score += score; + if ( score > (int)max_score ) + max_score = score; + + if ( alarm_image ) + { + snprintf( event_file, sizeof(event_file), analyse_file_format, path, frames ); + + Debug( 1, "Writing analysis frame %d", frames ); + if ( monitor->GetOptSaveJPEGs() & 2) { + WriteFrameImage( alarm_image, timestamp, event_file, true ); + } + } + } + + /* This makes viewing the diagnostic images impossible because it keeps deleting them + if ( config.record_diag_images ) + { + char diag_glob[PATH_MAX] = ""; + + snprintf( diag_glob, sizeof(diag_glob), "%s/%d/diag-*.jpg", config.dir_events, monitor->Id() ); + glob_t pglob; + int glob_status = glob( diag_glob, 0, 0, &pglob ); + if ( glob_status != 0 ) + { + if ( glob_status < 0 ) + { + Error( "Can't glob '%s': %s", diag_glob, strerror(errno) ); + } + else + { + Debug( 1, "Can't glob '%s': %d", diag_glob, glob_status ); + } + } + else + { + char new_diag_path[PATH_MAX] = ""; + for ( int i = 0; i < pglob.gl_pathc; i++ ) + { + char *diag_path = pglob.gl_pathv[i]; + + char *diag_file = strstr( diag_path, "diag-" ); + + if ( diag_file ) + { + snprintf( new_diag_path, sizeof(new_diag_path), general_file_format, path, frames, diag_file ); + + if ( rename( diag_path, new_diag_path ) < 0 ) + { + Error( "Can't rename '%s' to '%s': %s", diag_path, new_diag_path, strerror(errno) ); + } + } + } + } + globfree( &pglob ); + } + */ } bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) { - static char sql[ZM_SQL_SML_BUFSIZ]; + static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %d and unix_timestamp( EndTime ) > %ld order by Id asc limit 1", monitor_id, event_time ); + snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %d and unix_timestamp( EndTime ) > %ld order by Id asc limit 1", monitor_id, event_time ); - if ( mysql_query( &dbconn, sql ) ) + 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 ) ); + } + MYSQL_ROW dbrow = mysql_fetch_row( result ); + + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + + int init_event_id = atoi( dbrow[0] ); + + mysql_free_result( result ); + + loadEventData( init_event_id ); + + if ( event_time ) + { + curr_stream_time = event_time; + curr_frame_id = 1; + if ( event_time >= event_data->start_time ) { - 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 ) ); - } - MYSQL_ROW dbrow = mysql_fetch_row( result ); - - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - - int init_event_id = atoi( dbrow[0] ); - - mysql_free_result( result ); - - loadEventData( init_event_id ); - - if ( event_time ) - { - curr_stream_time = event_time; - curr_frame_id = 1; - if ( event_time >= event_data->start_time ) + for (unsigned int i = 0; i < event_data->frame_count; i++ ) + { + //Info( "eft %d > et %d", event_data->frames[i].timestamp, event_time ); + if ( event_data->frames[i].timestamp >= event_time ) { - for (unsigned int i = 0; i < event_data->frame_count; i++ ) - { - //Info( "eft %d > et %d", event_data->frames[i].timestamp, event_time ); - if ( event_data->frames[i].timestamp >= event_time ) - { - curr_frame_id = i+1; - Debug( 3, "Set cst:%.2f", curr_stream_time ); - Debug( 3, "Set cfid:%d", curr_frame_id ); - break; - } - } - Debug( 3, "Skipping %ld frames", event_data->frame_count ); + curr_frame_id = i+1; + Debug( 3, "Set cst:%.2f", curr_stream_time ); + Debug( 3, "Set cfid:%d", curr_frame_id ); + break; } + } + Debug( 3, "Skipping %ld frames", event_data->frame_count ); } - return( true ); + } + return( true ); } bool EventStream::loadInitialEventData( int init_event_id, unsigned int init_frame_id ) { - loadEventData( init_event_id ); + loadEventData( init_event_id ); - if ( init_frame_id ) - { - curr_stream_time = event_data->frames[init_frame_id-1].timestamp; - curr_frame_id = init_frame_id; - } - else - { - curr_stream_time = event_data->start_time; - } + if ( init_frame_id ) + { + curr_stream_time = event_data->frames[init_frame_id-1].timestamp; + curr_frame_id = init_frame_id; + } + else + { + curr_stream_time = event_data->start_time; + } - return( true ); + return( true ); } bool EventStream::loadEventData( int event_id ) { - static char sql[ZM_SQL_MED_BUFSIZ]; + static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "select M.Id, M.Name, E.StorageId, E.Frames, unix_timestamp( StartTime ) as StartTimestamp, max(F.Delta)-min(F.Delta) as Duration,E.DefaultVideo from Events as E inner join Monitors as M on E.MonitorId = M.Id inner join Frames as F on E.Id = F.EventId where E.Id = %d group by E.Id", event_id ); + snprintf( sql, sizeof(sql), "select M.Id, M.Name, E.StorageId, E.Frames, unix_timestamp( StartTime ) as StartTimestamp, max(F.Delta)-min(F.Delta) as Duration,E.DefaultVideo from Events as E inner join Monitors as M on E.MonitorId = M.Id inner join Frames as F on E.Id = F.EventId where E.Id = %d group by E.Id", event_id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + 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 ) ); - } + MYSQL_RES *result = mysql_store_result( &dbconn ); + if ( !result ) + { + Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } - if ( !mysql_num_rows( result ) ) - { - Fatal( "Unable to load event %d, not found in DB", event_id ); - } + if ( !mysql_num_rows( result ) ) + { + Fatal( "Unable to load event %d, not found in DB", event_id ); + } - MYSQL_ROW dbrow = mysql_fetch_row( result ); + MYSQL_ROW dbrow = mysql_fetch_row( result ); - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } - delete event_data; - event_data = new EventData; - event_data->event_id = event_id; - event_data->monitor_id = atoi( dbrow[0] ); - event_data->storage_id = dbrow[2] ? atoi( dbrow[2] ) : 0; - event_data->start_time = atoi(dbrow[4]); + delete event_data; + event_data = new EventData; + event_data->event_id = event_id; + event_data->monitor_id = atoi( dbrow[0] ); + event_data->storage_id = dbrow[2] ? atoi( dbrow[2] ) : 0; + event_data->start_time = atoi(dbrow[4]); - Storage * storage = new Storage( event_data->storage_id ); - const char *storage_path = storage->Path(); + Storage * storage = new Storage( event_data->storage_id ); + const char *storage_path = storage->Path(); - if ( config.use_deep_storage ) - { - struct tm *event_time = localtime( &event_data->start_time ); - if ( storage_path[0] == '/' ) - snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); - else - snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); - } + if ( config.use_deep_storage ) + { + struct tm *event_time = localtime( &event_data->start_time ); + if ( storage_path[0] == '/' ) + snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); else + snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); + } + else + { + if ( storage_path[0] == '/' ) + snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", storage_path, event_data->monitor_id, event_data->event_id ); + else + snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id ); + } + event_data->frame_count = dbrow[3] == NULL ? 0 : atoi(dbrow[3]); + event_data->duration = atof(dbrow[5]); + strncpy( event_data->video_file, dbrow[6], sizeof( event_data->video_file )-1 ); + + updateFrameRate( (double)event_data->frame_count/event_data->duration ); + + mysql_free_result( result ); + + snprintf( sql, sizeof(sql), "select FrameId, unix_timestamp( `TimeStamp` ), Delta from Frames where EventId = %d order by FrameId asc", event_id ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + + result = mysql_store_result( &dbconn ); + if ( !result ) + { + Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + + event_data->n_frames = mysql_num_rows( result ); + + event_data->frames = new FrameData[event_data->frame_count]; + int id, last_id = 0; + time_t timestamp, last_timestamp = event_data->start_time; + double delta, last_delta = 0.0; + while ( ( dbrow = mysql_fetch_row( result ) ) ) + { + id = atoi(dbrow[0]); + timestamp = atoi(dbrow[1]); + delta = atof(dbrow[2]); + int id_diff = id - last_id; + double frame_delta = (delta-last_delta)/id_diff; + if ( id_diff > 1 ) { - if ( storage_path[0] == '/' ) - snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", storage_path, event_data->monitor_id, event_data->event_id ); - else - snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id ); + for ( int i = last_id+1; i < id; i++ ) + { + event_data->frames[i-1].timestamp = (time_t)(last_timestamp + ((i-last_id)*frame_delta)); + event_data->frames[i-1].offset = (time_t)(event_data->frames[i-1].timestamp-event_data->start_time); + event_data->frames[i-1].delta = frame_delta; + event_data->frames[i-1].in_db = false; + } } - event_data->frame_count = dbrow[3] == NULL ? 0 : atoi(dbrow[3]); - event_data->duration = atof(dbrow[5]); - strncpy( event_data->video_file, dbrow[6], sizeof( event_data->video_file )-1 ); + event_data->frames[id-1].timestamp = timestamp; + event_data->frames[id-1].offset = (time_t)(event_data->frames[id-1].timestamp-event_data->start_time); + event_data->frames[id-1].delta = id>1?frame_delta:0.0; + event_data->frames[id-1].in_db = true; + last_id = id; + last_delta = delta; + last_timestamp = timestamp; + } + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } - updateFrameRate( (double)event_data->frame_count/event_data->duration ); + //for ( int i = 0; i < 250; i++ ) + //{ + //Info( "%d -> %d @ %f (%d)", i+1, event_data->frames[i].timestamp, event_data->frames[i].delta, event_data->frames[i].in_db ); + //} - mysql_free_result( result ); + mysql_free_result( result ); - snprintf( sql, sizeof(sql), "select FrameId, unix_timestamp( `TimeStamp` ), Delta from Frames where EventId = %d order by FrameId asc", event_id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + if ( forceEventChange || mode == MODE_ALL_GAPLESS ) + { + if ( replay_rate > 0 ) + curr_stream_time = event_data->frames[0].timestamp; + else + curr_stream_time = event_data->frames[event_data->frame_count-1].timestamp; + } + Debug( 2, "Event:%ld, Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration ); - result = mysql_store_result( &dbconn ); - if ( !result ) - { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - - event_data->n_frames = mysql_num_rows( result ); - - event_data->frames = new FrameData[event_data->frame_count]; - int id, last_id = 0; - time_t timestamp, last_timestamp = event_data->start_time; - double delta, last_delta = 0.0; - while ( ( dbrow = mysql_fetch_row( result ) ) ) - { - id = atoi(dbrow[0]); - timestamp = atoi(dbrow[1]); - delta = atof(dbrow[2]); - int id_diff = id - last_id; - double frame_delta = (delta-last_delta)/id_diff; - if ( id_diff > 1 ) - { - for ( int i = last_id+1; i < id; i++ ) - { - event_data->frames[i-1].timestamp = (time_t)(last_timestamp + ((i-last_id)*frame_delta)); - event_data->frames[i-1].offset = (time_t)(event_data->frames[i-1].timestamp-event_data->start_time); - event_data->frames[i-1].delta = frame_delta; - event_data->frames[i-1].in_db = false; - } - } - event_data->frames[id-1].timestamp = timestamp; - event_data->frames[id-1].offset = (time_t)(event_data->frames[id-1].timestamp-event_data->start_time); - event_data->frames[id-1].delta = id>1?frame_delta:0.0; - event_data->frames[id-1].in_db = true; - last_id = id; - last_delta = delta; - last_timestamp = timestamp; - } - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - - //for ( int i = 0; i < 250; i++ ) - //{ - //Info( "%d -> %d @ %f (%d)", i+1, event_data->frames[i].timestamp, event_data->frames[i].delta, event_data->frames[i].in_db ); - //} - - mysql_free_result( result ); - - if ( forceEventChange || mode == MODE_ALL_GAPLESS ) - { - if ( replay_rate > 0 ) - curr_stream_time = event_data->frames[0].timestamp; - else - curr_stream_time = event_data->frames[event_data->frame_count-1].timestamp; - } - Debug( 2, "Event:%ld, Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration ); - - return( true ); + return( true ); } void EventStream::processCommand( const CmdMsg *msg ) { - Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ) + 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 : + case CMD_PAUSE : { - Debug( 1, "Got PAUSE command" ); + Debug( 1, "Got PAUSE command" ); - // Set paused flag - paused = true; - replay_rate = ZM_RATE_BASE; - last_frame_sent = TV_2_FLOAT( now ); - break; + // Set paused flag + paused = true; + replay_rate = ZM_RATE_BASE; + last_frame_sent = TV_2_FLOAT( now ); + break; } - case CMD_PLAY : + case CMD_PLAY : { - Debug( 1, "Got PLAY command" ); - if ( paused ) - { - // Clear paused flag - paused = false; - } - - // If we are in single event mode and at the last frame, replay the current event - if ( (mode == MODE_SINGLE) && ((unsigned int)curr_frame_id == event_data->frame_count) ) - curr_frame_id = 1; - - replay_rate = ZM_RATE_BASE; - break; - } - case CMD_VARPLAY : - { - Debug( 1, "Got VARPLAY command" ); - if ( paused ) - { - // Clear paused flag - paused = false; - } - 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" ); - + Debug( 1, "Got PLAY command" ); + if ( paused ) + { // Clear paused flag paused = false; - break; + } + + // If we are in single event mode and at the last frame, replay the current event + if ( (mode == MODE_SINGLE) && ((unsigned int)curr_frame_id == event_data->frame_count) ) + curr_frame_id = 1; + + replay_rate = ZM_RATE_BASE; + break; } - case CMD_FASTFWD : + case CMD_VARPLAY : { - Debug( 1, "Got FAST FWD command" ); - if ( paused ) - { - // Clear paused flag - paused = false; - } - // 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 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 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 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_PREV : - { - Debug( 1, "Got PREV command" ); - if ( replay_rate >= 0 ) - curr_frame_id = 0; - else - curr_frame_id = event_data->frame_count+1; + Debug( 1, "Got VARPLAY command" ); + if ( paused ) + { + // Clear paused flag paused = false; - forceEventChange = true; - break; + } + replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768; + break; } - case CMD_NEXT : + case CMD_STOP : { - Debug( 1, "Got NEXT command" ); - if ( replay_rate >= 0 ) - curr_frame_id = event_data->frame_count+1; - else - curr_frame_id = 0; + Debug( 1, "Got STOP command" ); + + // Clear paused flag + paused = false; + break; + } + case CMD_FASTFWD : + { + Debug( 1, "Got FAST FWD command" ); + if ( paused ) + { + // Clear paused flag paused = false; - forceEventChange = true; - break; + } + // 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_SEEK : + case CMD_SLOWFWD : { - int offset = ((unsigned char)msg->msg_data[1]<<24)|((unsigned char)msg->msg_data[2]<<16)|((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; - curr_frame_id = (int)(event_data->frame_count*offset/event_data->duration); - Debug( 1, "Got SEEK command, to %d (new cfid: %d)", offset, curr_frame_id ); - break; + Debug( 1, "Got SLOW FWD command" ); + // Set paused flag + paused = true; + // Set play rate + replay_rate = ZM_RATE_BASE; + // Set step + step = 1; + break; } - case CMD_QUERY : + case CMD_SLOWREV : { - Debug( 1, "Got QUERY command, sending STATUS" ); - break; + Debug( 1, "Got SLOW REV command" ); + // Set paused flag + paused = true; + // Set play rate + replay_rate = ZM_RATE_BASE; + // Set step + step = -1; + break; } - case CMD_QUIT : + case CMD_FASTREV : { - Info ("User initiated exit - CMD_QUIT"); - break; + Debug( 1, "Got FAST REV command" ); + if ( paused ) + { + // Clear paused flag + paused = false; + } + // 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; } - default : + case CMD_ZOOMIN : { - // Do nothing, for now + 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_PREV : + { + Debug( 1, "Got PREV command" ); + if ( replay_rate >= 0 ) + curr_frame_id = 0; + else + curr_frame_id = event_data->frame_count+1; + paused = false; + forceEventChange = true; + break; + } + case CMD_NEXT : + { + Debug( 1, "Got NEXT command" ); + if ( replay_rate >= 0 ) + curr_frame_id = event_data->frame_count+1; + else + curr_frame_id = 0; + paused = false; + forceEventChange = true; + break; + } + case CMD_SEEK : + { + int offset = ((unsigned char)msg->msg_data[1]<<24)|((unsigned char)msg->msg_data[2]<<16)|((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; + curr_frame_id = (int)(event_data->frame_count*offset/event_data->duration); + Debug( 1, "Got SEEK command, to %d (new cfid: %d)", offset, curr_frame_id ); + break; + } + case CMD_QUERY : + { + Debug( 1, "Got QUERY command, sending STATUS" ); + break; + } + case CMD_QUIT : + { + Info ("User initiated exit - CMD_QUIT"); + break; + } + default : + { + // Do nothing, for now } } - struct { - int event; - int progress; - int rate; - int zoom; - bool paused; - } status_data; + struct { + int event; + int progress; + int rate; + int zoom; + bool paused; + } status_data; - status_data.event = event_data->event_id; - status_data.progress = (int)event_data->frames[curr_frame_id-1].offset; - status_data.rate = replay_rate; - status_data.zoom = zoom; - status_data.paused = paused; - Debug( 2, "E:%d, P:%d, p:%d R:%d, Z:%d", - status_data.event, - status_data.paused, - status_data.progress, - status_data.rate, - status_data.zoom - ); + status_data.event = event_data->event_id; + status_data.progress = (int)event_data->frames[curr_frame_id-1].offset; + status_data.rate = replay_rate; + status_data.zoom = zoom; + status_data.paused = paused; + Debug( 2, "E:%d, P:%d, p:%d R:%d, Z:%d", + status_data.event, + status_data.paused, + status_data.progress, + status_data.rate, + status_data.zoom + ); - DataMsg status_msg; - status_msg.msg_type = MSG_DATA_EVENT; - memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) ); - if ( sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) ) < 0 ) + DataMsg status_msg; + status_msg.msg_type = MSG_DATA_EVENT; + memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) ); + if ( sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) ) < 0 ) + { + //if ( errno != EAGAIN ) { - //if ( errno != EAGAIN ) - { - Error( "Can't sendto on sd %d: %s", sd, strerror(errno) ); - exit( -1 ); - } + Error( "Can't sendto on sd %d: %s", sd, strerror(errno) ); + exit( -1 ); } - // quit after sending a status, if this was a quit request - if ((MsgCommand)msg->msg_data[0]==CMD_QUIT) - exit(0); + } + // quit after sending a status, if this was a quit request + if ((MsgCommand)msg->msg_data[0]==CMD_QUIT) + exit(0); - updateFrameRate( (double)event_data->frame_count/event_data->duration ); + updateFrameRate( (double)event_data->frame_count/event_data->duration ); } void EventStream::checkEventLoaded() { - bool reload_event = false; - static char sql[ZM_SQL_SML_BUFSIZ]; + bool reload_event = false; + static char sql[ZM_SQL_SML_BUFSIZ]; - if ( curr_frame_id <= 0 ) + if ( curr_frame_id <= 0 ) + { + snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id < %ld order by Id desc limit 1", event_data->monitor_id, event_data->event_id ); + reload_event = true; + } + else if ( (unsigned int)curr_frame_id > event_data->frame_count ) + { + snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id > %ld order by Id asc limit 1", event_data->monitor_id, event_data->event_id ); + reload_event = true; + } + + if ( reload_event ) + { + if ( forceEventChange || mode != MODE_SINGLE ) { - snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id < %ld order by Id desc limit 1", event_data->monitor_id, event_data->event_id ); - reload_event = true; - } - else if ( (unsigned int)curr_frame_id > event_data->frame_count ) - { - snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id > %ld order by Id asc limit 1", event_data->monitor_id, event_data->event_id ); - reload_event = true; - } + //Info( "SQL:%s", sql ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } - if ( reload_event ) - { - if ( forceEventChange || mode != MODE_SINGLE ) - { - //Info( "SQL:%s", sql ); - 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 ) ); + } + MYSQL_ROW dbrow = mysql_fetch_row( result ); - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) - { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - MYSQL_ROW dbrow = mysql_fetch_row( result ); + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + if ( dbrow ) + { + int event_id = atoi(dbrow[0]); + Debug( 1, "Loading new event %d", event_id ); - if ( dbrow ) - { - int event_id = atoi(dbrow[0]); - Debug( 1, "Loading new event %d", event_id ); + loadEventData( event_id ); - loadEventData( event_id ); - - Debug( 2, "Current frame id = %d", curr_frame_id ); - if ( replay_rate < 0 ) - curr_frame_id = event_data->frame_count; - else - curr_frame_id = 1; - Debug( 2, "New frame id = %d", curr_frame_id ); - } - else - { - if ( curr_frame_id <= 0 ) - curr_frame_id = 1; - else - curr_frame_id = event_data->frame_count; - paused = true; - } - mysql_free_result( result ); - forceEventChange = false; - } + Debug( 2, "Current frame id = %d", curr_frame_id ); + if ( replay_rate < 0 ) + curr_frame_id = event_data->frame_count; else - { - if ( curr_frame_id <= 0 ) - curr_frame_id = 1; - else - curr_frame_id = event_data->frame_count; - paused = true; - } + curr_frame_id = 1; + Debug( 2, "New frame id = %d", curr_frame_id ); + } + else + { + if ( curr_frame_id <= 0 ) + curr_frame_id = 1; + else + curr_frame_id = event_data->frame_count; + paused = true; + } + mysql_free_result( result ); + forceEventChange = false; } + else + { + if ( curr_frame_id <= 0 ) + curr_frame_id = 1; + else + curr_frame_id = event_data->frame_count; + paused = true; + } + } } Image * EventStream::getImage( ) { - Event::Initialise(); - static char filepath[PATH_MAX]; - - Debug( 2, "EventStream::getImage path(%s) frame(%d)", event_data->path, curr_frame_id ); - snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id ); - Debug( 2, "EventStream::getImage path(%s) ", filepath, curr_frame_id ); - Image *image = new Image( filepath ); - return image; + Event::Initialise(); + static char filepath[PATH_MAX]; + + Debug( 2, "EventStream::getImage path(%s) frame(%d)", event_data->path, curr_frame_id ); + snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id ); + Debug( 2, "EventStream::getImage path(%s) ", filepath, curr_frame_id ); + Image *image = new Image( filepath ); + return image; } bool EventStream::sendFrame( int delta_us ) { - Debug( 2, "Sending frame %d", curr_frame_id ); + Debug( 2, "Sending frame %d", curr_frame_id ); - static char filepath[PATH_MAX]; - static struct stat filestat; - FILE *fdj = NULL; - - snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id ); + static char filepath[PATH_MAX]; + static struct stat filestat; + FILE *fdj = NULL; + + snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id ); #if HAVE_LIBAVCODEC - if ( type == STREAM_MPEG ) + if ( type == STREAM_MPEG ) + { + Image image( filepath ); + + Image *send_image = prepareImage( &image ); + + if ( !vid_stream ) { - Image image( filepath ); + 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(); + } + /* double pts = */ vid_stream->EncodeFrame( send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_us*1000 ); + } + else +#endif // HAVE_LIBAVCODEC + { + static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; - Image *send_image = prepareImage( &image ); + int img_buffer_size = 0; + uint8_t *img_buffer = temp_img_buffer; - if ( !vid_stream ) - { - 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(); - } - /* double pts = */ vid_stream->EncodeFrame( send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_us*1000 ); + bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); + + fprintf( stdout, "--ZoneMinderFrame\r\n" ); + + if ( type != STREAM_JPEG ) + send_raw = false; + + if ( send_raw ) + { + fdj = fopen( filepath, "rb" ); + if ( !fdj ) + { + Error( "Can't open %s: %s", filepath, strerror(errno) ); + return( false ); + } +#if HAVE_SENDFILE + if( fstat(fileno(fdj),&filestat) < 0 ) { + Error( "Failed getting information about file %s: %s", filepath, strerror(errno) ); + return( false ); + } +#else + img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); +#endif } else -#endif // HAVE_LIBAVCODEC { - static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; + Image image( filepath ); - int img_buffer_size = 0; - uint8_t *img_buffer = temp_img_buffer; + Image *send_image = prepareImage( &image ); - bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); - - fprintf( stdout, "--ZoneMinderFrame\r\n" ); - - if ( type != STREAM_JPEG ) - send_raw = false; - - if ( send_raw ) - { - fdj = fopen( filepath, "rb" ); - if ( !fdj ) - { - Error( "Can't open %s: %s", filepath, strerror(errno) ); - return( false ); - } -#if HAVE_SENDFILE - if( fstat(fileno(fdj),&filestat) < 0 ) { - Error( "Failed getting information about file %s: %s", filepath, strerror(errno) ); - return( false ); - } -#else - img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); -#endif - } - else - { - Image image( filepath ); - - Image *send_image = prepareImage( &image ); - - switch( type ) - { - case STREAM_JPEG : - send_image->EncodeJpeg( img_buffer, &img_buffer_size ); - break; - case STREAM_ZIP : + switch( type ) + { + case STREAM_JPEG : + send_image->EncodeJpeg( img_buffer, &img_buffer_size ); + break; + case STREAM_ZIP : #if HAVE_ZLIB_H - unsigned long zip_buffer_size; - send_image->Zip( img_buffer, &zip_buffer_size ); - img_buffer_size = zip_buffer_size; - break; + unsigned long zip_buffer_size; + send_image->Zip( img_buffer, &zip_buffer_size ); + img_buffer_size = zip_buffer_size; + break; #else - Error("zlib is required for zipped images. Falling back to raw image"); - type = STREAM_RAW; + Error("zlib is required for zipped images. Falling back to raw image"); + type = STREAM_RAW; #endif // HAVE_ZLIB_H - case STREAM_RAW : - img_buffer = (uint8_t*)(send_image->Buffer()); - img_buffer_size = send_image->Size(); - break; - default: - Fatal( "Unexpected frame type %d", type ); - break; - } - } - - switch( type ) - { - case STREAM_JPEG : - fprintf( stdout, "Content-Type: image/jpeg\r\n" ); - break; - case STREAM_RAW : - fprintf( stdout, "Content-Type: image/x-rgb\r\n" ); - break; - case STREAM_ZIP : - fprintf( stdout, "Content-Type: image/x-rgbz\r\n" ); - break; - default : - Fatal( "Unexpected frame type %d", type ); - break; - } - - - if(send_raw) { -#if HAVE_SENDFILE - fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size ); - if(zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) { - /* sendfile() failed, use standard way instead */ - img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); - if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { - Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno)); - return( false ); - } - } -#else - fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); - if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { - Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno)); - return( false ); - } -#endif - fclose(fdj); /* Close the file handle */ - } else { - fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); - if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) - { - Error( "Unable to send stream frame: %s", strerror(errno) ); - return( false ); - } - } - - fprintf( stdout, "\r\n\r\n" ); - fflush( stdout ); + case STREAM_RAW : + img_buffer = (uint8_t*)(send_image->Buffer()); + img_buffer_size = send_image->Size(); + break; + default: + Fatal( "Unexpected frame type %d", type ); + break; + } } - last_frame_sent = TV_2_FLOAT( now ); - return( true ); + + switch( type ) + { + case STREAM_JPEG : + fprintf( stdout, "Content-Type: image/jpeg\r\n" ); + break; + case STREAM_RAW : + fprintf( stdout, "Content-Type: image/x-rgb\r\n" ); + break; + case STREAM_ZIP : + fprintf( stdout, "Content-Type: image/x-rgbz\r\n" ); + break; + default : + Fatal( "Unexpected frame type %d", type ); + break; + } + + + if(send_raw) { +#if HAVE_SENDFILE + fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size ); + if(zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) { + /* sendfile() failed, use standard way instead */ + img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); + if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { + Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno)); + return( false ); + } + } +#else + fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); + if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { + Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno)); + return( false ); + } +#endif + fclose(fdj); /* Close the file handle */ + } else { + fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); + if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) + { + Error( "Unable to send stream frame: %s", strerror(errno) ); + return( false ); + } + } + + fprintf( stdout, "\r\n\r\n" ); + fflush( stdout ); + } + last_frame_sent = TV_2_FLOAT( now ); + return( true ); } void EventStream::runStream() { - Event::Initialise(); + Event::Initialise(); - openComms(); + openComms(); - checkInitialised(); + checkInitialised(); - updateFrameRate( (double)event_data->frame_count/event_data->duration ); + updateFrameRate( (double)event_data->frame_count/event_data->duration ); - if ( type == STREAM_JPEG ) - fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); + if ( type == STREAM_JPEG ) + fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); - if ( !event_data ) + if ( !event_data ) + { + sendTextFrame( "No event data found" ); + exit( 0 ); + } + + unsigned int delta_us = 0; + while( !zm_terminate ) + { + gettimeofday( &now, NULL ); + + while(checkCommandQueue()); + + if ( step != 0 ) + curr_frame_id += step; + + checkEventLoaded(); + + // Get current frame data + FrameData *frame_data = &event_data->frames[curr_frame_id-1]; + + //Info( "cst:%.2f", curr_stream_time ); + //Info( "cfid:%d", curr_frame_id ); + //Info( "fdt:%d", frame_data->timestamp ); + if ( !paused ) { - sendTextFrame( "No event data found" ); - exit( 0 ); + bool in_event = true; + double time_to_event = 0; + if ( replay_rate > 0 ) + { + time_to_event = event_data->frames[0].timestamp - curr_stream_time; + if ( time_to_event > 0 ) + in_event = false; + } + else if ( replay_rate < 0 ) + { + time_to_event = curr_stream_time - event_data->frames[event_data->frame_count-1].timestamp; + if ( time_to_event > 0 ) + in_event = false; + } + if ( !in_event ) + { + double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; + if ( actual_delta_time > 1 ) + { + static char frame_text[64]; + snprintf( frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event ); + if ( !sendTextFrame( frame_text ) ) + zm_terminate = true; + } + //else + //{ + usleep( STREAM_PAUSE_WAIT ); + //curr_stream_time += (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000)); + curr_stream_time += (1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000); + //} + continue; + } } - unsigned int delta_us = 0; - while( !zm_terminate ) + // Figure out if we should send this frame + bool send_frame = false; + if ( !paused ) { - gettimeofday( &now, NULL ); - - while(checkCommandQueue()); - - if ( step != 0 ) - curr_frame_id += step; - - checkEventLoaded(); - - // Get current frame data - FrameData *frame_data = &event_data->frames[curr_frame_id-1]; - - //Info( "cst:%.2f", curr_stream_time ); - //Info( "cfid:%d", curr_frame_id ); - //Info( "fdt:%d", frame_data->timestamp ); - if ( !paused ) - { - bool in_event = true; - double time_to_event = 0; - if ( replay_rate > 0 ) - { - time_to_event = event_data->frames[0].timestamp - curr_stream_time; - if ( time_to_event > 0 ) - in_event = false; - } - else if ( replay_rate < 0 ) - { - time_to_event = curr_stream_time - event_data->frames[event_data->frame_count-1].timestamp; - if ( time_to_event > 0 ) - in_event = false; - } - if ( !in_event ) - { - double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; - if ( actual_delta_time > 1 ) - { - static char frame_text[64]; - snprintf( frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event ); - if ( !sendTextFrame( frame_text ) ) - zm_terminate = true; - } - //else - //{ - usleep( STREAM_PAUSE_WAIT ); - //curr_stream_time += (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000)); - curr_stream_time += (1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000); - //} - continue; - } - } - - // Figure out if we should send this frame - bool send_frame = false; - if ( !paused ) - { - // If we are streaming and this frame is due to be sent - if ( ((curr_frame_id-1)%frame_mod) == 0 ) - { - delta_us = (unsigned int)(frame_data->delta * 1000000); - // if effective > base we should speed up frame delivery - delta_us = (unsigned int)((delta_us * base_fps)/effective_fps); - // but must not exceed maxfps - delta_us = max(delta_us, 1000000 / maxfps); - send_frame = true; - } - } - else if ( step != 0 ) - { - // We are paused and are just stepping forward or backward one frame - step = 0; - send_frame = true; - } - else - { - // We are paused, and doing nothing - double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; - if ( actual_delta_time > MAX_STREAM_DELAY ) - { - // Send keepalive - Debug( 2, "Sending keepalive frame" ); - send_frame = true; - } - } - - if ( send_frame ) - if ( !sendFrame( delta_us ) ) - zm_terminate = true; - - curr_stream_time = frame_data->timestamp; - - if ( !paused ) - { - curr_frame_id += replay_rate>0?1:-1; - if ( send_frame && type != STREAM_MPEG ) - { - Debug( 3, "dUs: %d", delta_us ); - usleep( delta_us ); - } - } - else - { - usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) ); - } + // If we are streaming and this frame is due to be sent + if ( ((curr_frame_id-1)%frame_mod) == 0 ) + { + delta_us = (unsigned int)(frame_data->delta * 1000000); + // if effective > base we should speed up frame delivery + delta_us = (unsigned int)((delta_us * base_fps)/effective_fps); + // but must not exceed maxfps + delta_us = max(delta_us, 1000000 / maxfps); + send_frame = true; + } } + else if ( step != 0 ) + { + // We are paused and are just stepping forward or backward one frame + step = 0; + send_frame = true; + } + else + { + // We are paused, and doing nothing + double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; + if ( actual_delta_time > MAX_STREAM_DELAY ) + { + // Send keepalive + Debug( 2, "Sending keepalive frame" ); + send_frame = true; + } + } + + if ( send_frame ) + if ( !sendFrame( delta_us ) ) + zm_terminate = true; + + curr_stream_time = frame_data->timestamp; + + if ( !paused ) + { + curr_frame_id += replay_rate>0?1:-1; + if ( send_frame && type != STREAM_MPEG ) + { + Debug( 3, "dUs: %d", delta_us ); + usleep( delta_us ); + } + } + else + { + usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) ); + } + } #if HAVE_LIBAVCODEC - if ( type == STREAM_MPEG ) - delete vid_stream; + if ( type == STREAM_MPEG ) + delete vid_stream; #endif // HAVE_LIBAVCODEC - closeComms(); + closeComms(); } diff --git a/src/zm_event.h b/src/zm_event.h index 9f96f3810..576e0e869 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -42,210 +42,210 @@ class Zone; class Monitor; -#define MAX_PRE_ALARM_FRAMES 16 // Maximum number of prealarm frames that can be stored +#define MAX_PRE_ALARM_FRAMES 16 // Maximum number of prealarm frames that can be stored // // Class describing events, i.e. captured periods of activity. // class Event { -friend class EventStream; + friend class EventStream; -protected: - static bool initialised; - static char capture_file_format[PATH_MAX]; - static char analyse_file_format[PATH_MAX]; - static char general_file_format[PATH_MAX]; - static char video_file_format[PATH_MAX]; + protected: + static bool initialised; + static char capture_file_format[PATH_MAX]; + static char analyse_file_format[PATH_MAX]; + static char general_file_format[PATH_MAX]; + static char video_file_format[PATH_MAX]; -protected: - static int sd; + protected: + static int sd; -public: - typedef std::set StringSet; - typedef std::map StringSetMap; + public: + typedef std::set StringSet; + typedef std::map StringSetMap; -protected: - typedef enum { NORMAL, BULK, ALARM } FrameType; + protected: + typedef enum { NORMAL, BULK, ALARM } FrameType; - struct PreAlarmData - { - Image *image; - struct timeval timestamp; - unsigned int score; - Image *alarm_frame; - }; + struct PreAlarmData + { + Image *image; + struct timeval timestamp; + unsigned int score; + Image *alarm_frame; + }; - static int pre_alarm_count; - static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES]; + static int pre_alarm_count; + static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES]; -protected: - unsigned int id; - Monitor *monitor; - struct timeval start_time; - struct timeval end_time; - std::string cause; - StringSetMap noteSetMap; - bool videoEvent; - int frames; - int alarm_frames; - unsigned int tot_score; - unsigned int max_score; - char path[PATH_MAX]; - VideoWriter* videowriter; - FILE* timecodes_fd; - char video_name[PATH_MAX]; - char video_file[PATH_MAX]; - char timecodes_name[PATH_MAX]; - char timecodes_file[PATH_MAX]; + protected: + unsigned int id; + Monitor *monitor; + struct timeval start_time; + struct timeval end_time; + std::string cause; + StringSetMap noteSetMap; + bool videoEvent; + int frames; + int alarm_frames; + unsigned int tot_score; + unsigned int max_score; + char path[PATH_MAX]; + VideoWriter* videowriter; + FILE* timecodes_fd; + char video_name[PATH_MAX]; + char video_file[PATH_MAX]; + char timecodes_name[PATH_MAX]; + char timecodes_file[PATH_MAX]; -protected: - int last_db_frame; + protected: + int last_db_frame; -protected: - static void Initialise() - { - if ( initialised ) - return; + protected: + static void Initialise() + { + if ( initialised ) + return; - snprintf( capture_file_format, sizeof(capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits ); - snprintf( analyse_file_format, sizeof(analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits ); - snprintf( general_file_format, sizeof(general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits ); - snprintf( video_file_format, sizeof(video_file_format), "%%s/%%s"); + snprintf( capture_file_format, sizeof(capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits ); + snprintf( analyse_file_format, sizeof(analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits ); + snprintf( general_file_format, sizeof(general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits ); + snprintf( video_file_format, sizeof(video_file_format), "%%s/%%s"); - initialised = true; - } + initialised = true; + } - void createNotes( std::string ¬es ); + void createNotes( std::string ¬es ); -public: - static bool OpenFrameSocket( int ); - static bool ValidateFrameSocket( int ); + public: + static bool OpenFrameSocket( int ); + static bool ValidateFrameSocket( int ); -public: - Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false ); - ~Event(); + public: + Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false ); + ~Event(); - int Id() const { return( id ); } - const std::string &Cause() { return( cause ); } - int Frames() const { return( frames ); } - int AlarmFrames() const { return( alarm_frames ); } + int Id() const { return( id ); } + const std::string &Cause() { return( cause ); } + int Frames() const { return( frames ); } + int AlarmFrames() const { return( alarm_frames ); } - const struct timeval &StartTime() const { return( start_time ); } - const struct timeval &EndTime() const { return( end_time ); } - struct timeval &EndTime() { return( end_time ); } + const struct timeval &StartTime() const { return( start_time ); } + const struct timeval &EndTime() const { return( end_time ); } + struct timeval &EndTime() { return( end_time ); } - bool SendFrameImage( const Image *image, bool alarm_frame=false ); - bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false ); - bool WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ); + bool SendFrameImage( const Image *image, bool alarm_frame=false ); + bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false ); + bool WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ); - void updateNotes( const StringSetMap &stringSetMap ); + void updateNotes( const StringSetMap &stringSetMap ); - void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); - void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ); + void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); + void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ); -private: - void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ); + private: + void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ); -public: - static const char *getSubPath( struct tm *time ) + public: + static const char *getSubPath( struct tm *time ) + { + static char subpath[PATH_MAX] = ""; + snprintf( subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec ); + return( subpath ); + } + static const char *getSubPath( time_t *time ) + { + return( Event::getSubPath( localtime( time ) ) ); + } + + char* getEventFile(void){ + return video_file; + } + + public: + static int PreAlarmCount() + { + return( pre_alarm_count ); + } + static void EmptyPreAlarmFrames() + { + if ( pre_alarm_count > 0 ) { - static char subpath[PATH_MAX] = ""; - snprintf( subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec ); - return( subpath ); + for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ ) + { + delete pre_alarm_data[i].image; + delete pre_alarm_data[i].alarm_frame; + } + memset( pre_alarm_data, 0, sizeof(pre_alarm_data) ); } - static const char *getSubPath( time_t *time ) + pre_alarm_count = 0; + } + static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ) + { + pre_alarm_data[pre_alarm_count].image = new Image( *image ); + pre_alarm_data[pre_alarm_count].timestamp = timestamp; + pre_alarm_data[pre_alarm_count].score = score; + if ( alarm_frame ) { - return( Event::getSubPath( localtime( time ) ) ); + pre_alarm_data[pre_alarm_count].alarm_frame = new Image( *alarm_frame ); } - - char* getEventFile(void){ - return video_file; + pre_alarm_count++; + } + void SavePreAlarmFrames() + { + for ( int i = 0; i < pre_alarm_count; i++ ) + { + AddFrame( pre_alarm_data[i].image, pre_alarm_data[i].timestamp, pre_alarm_data[i].score, pre_alarm_data[i].alarm_frame ); } - -public: - static int PreAlarmCount() - { - return( pre_alarm_count ); - } - static void EmptyPreAlarmFrames() - { - if ( pre_alarm_count > 0 ) - { - for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ ) - { - delete pre_alarm_data[i].image; - delete pre_alarm_data[i].alarm_frame; - } - memset( pre_alarm_data, 0, sizeof(pre_alarm_data) ); - } - pre_alarm_count = 0; - } - static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ) - { - pre_alarm_data[pre_alarm_count].image = new Image( *image ); - pre_alarm_data[pre_alarm_count].timestamp = timestamp; - pre_alarm_data[pre_alarm_count].score = score; - if ( alarm_frame ) - { - pre_alarm_data[pre_alarm_count].alarm_frame = new Image( *alarm_frame ); - } - pre_alarm_count++; - } - void SavePreAlarmFrames() - { - for ( int i = 0; i < pre_alarm_count; i++ ) - { - AddFrame( pre_alarm_data[i].image, pre_alarm_data[i].timestamp, pre_alarm_data[i].score, pre_alarm_data[i].alarm_frame ); - } - EmptyPreAlarmFrames(); - } + EmptyPreAlarmFrames(); + } }; class EventStream : public StreamBase { -public: + public: typedef enum { MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode; -protected: + protected: struct FrameData { - //unsigned long id; - time_t timestamp; - time_t offset; - double delta; - bool in_db; + //unsigned long id; + time_t timestamp; + time_t offset; + double delta; + bool in_db; }; struct EventData { - unsigned long event_id; - unsigned long monitor_id; - unsigned long storage_id; - unsigned long frame_count; - time_t start_time; - double duration; - char path[PATH_MAX]; - int n_frames; - FrameData *frames; - char video_file[PATH_MAX]; + unsigned long event_id; + unsigned long monitor_id; + unsigned long storage_id; + unsigned long frame_count; + time_t start_time; + double duration; + char path[PATH_MAX]; + int n_frames; + FrameData *frames; + char video_file[PATH_MAX]; }; -protected: + protected: static const int STREAM_PAUSE_WAIT = 250000; // Microseconds static const StreamMode DEFAULT_MODE = MODE_SINGLE; -protected: + protected: StreamMode mode; bool forceEventChange; -protected: + protected: int curr_frame_id; double curr_stream_time; EventData *event_data; -protected: + protected: bool loadEventData( int event_id ); bool loadInitialEventData( int init_event_id, unsigned int init_frame_id ); bool loadInitialEventData( int monitor_id, time_t event_time ); @@ -254,34 +254,34 @@ protected: void processCommand( const CmdMsg *msg ); bool sendFrame( int delta_us ); -public: + public: EventStream() { - mode = DEFAULT_MODE; + mode = DEFAULT_MODE; - forceEventChange = false; + forceEventChange = false; - curr_frame_id = 0; - curr_stream_time = 0.0; + curr_frame_id = 0; + curr_stream_time = 0.0; - event_data = 0; + event_data = 0; } - void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) + void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) { - loadInitialEventData( init_event_id, init_frame_id ); - loadMonitor( event_data->monitor_id ); + loadInitialEventData( init_event_id, init_frame_id ); + loadMonitor( event_data->monitor_id ); } - void setStreamStart( int monitor_id, time_t event_time ) + void setStreamStart( int monitor_id, time_t event_time ) { - loadInitialEventData( monitor_id, event_time ); - loadMonitor( monitor_id ); + loadInitialEventData( monitor_id, event_time ); + loadMonitor( monitor_id ); } void setStreamMode( StreamMode p_mode ) { - mode = p_mode; + mode = p_mode; } void runStream(); - Image *getImage(); + Image *getImage(); }; #endif // ZM_EVENT_H diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 70f77ca4c..a4d4b4378 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -48,505 +48,505 @@ // class Monitor { -friend class MonitorStream; + friend class MonitorStream; -public: - typedef enum - { - QUERY=0, - CAPTURE, - ANALYSIS - } Purpose; + public: + typedef enum + { + QUERY=0, + CAPTURE, + ANALYSIS + } Purpose; - typedef enum - { - NONE=1, - MONITOR, - MODECT, - RECORD, - MOCORD, - NODECT - } Function; + typedef enum + { + NONE=1, + MONITOR, + MODECT, + RECORD, + MOCORD, + NODECT + } Function; - typedef enum - { - ROTATE_0=1, - ROTATE_90, - ROTATE_180, - ROTATE_270, - FLIP_HORI, - FLIP_VERT - } Orientation; + typedef enum + { + ROTATE_0=1, + ROTATE_90, + ROTATE_180, + ROTATE_270, + FLIP_HORI, + FLIP_VERT + } Orientation; - typedef enum - { - IDLE, - PREALARM, - ALARM, - ALERT, - TAPE - } State; + typedef enum + { + IDLE, + PREALARM, + ALARM, + ALERT, + TAPE + } State; -protected: - typedef std::set ZoneSet; + protected: + typedef std::set ZoneSet; - typedef enum { GET_SETTINGS=0x1, SET_SETTINGS=0x2, RELOAD=0x4, SUSPEND=0x10, RESUME=0x20 } Action; + typedef enum { GET_SETTINGS=0x1, SET_SETTINGS=0x2, RELOAD=0x4, SUSPEND=0x10, RESUME=0x20 } Action; - typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode; + typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode; - /* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */ - typedef struct - { - uint32_t size; /* +0 */ - uint32_t last_write_index; /* +4 */ - uint32_t last_read_index; /* +8 */ - uint32_t state; /* +12 */ - uint32_t last_event; /* +16 */ - uint32_t action; /* +20 */ - int32_t brightness; /* +24 */ - int32_t hue; /* +28 */ - int32_t colour; /* +32 */ - int32_t contrast; /* +36 */ - int32_t alarm_x; /* +40 */ - int32_t alarm_y; /* +44 */ - uint8_t valid; /* +48 */ - uint8_t active; /* +49 */ - uint8_t signal; /* +50 */ - uint8_t format; /* +51 */ - uint32_t imagesize; /* +52 */ - uint32_t epadding1; /* +56 */ - uint32_t epadding2; /* +60 */ - /* - ** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038. - ** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16. - */ - union { /* +64 */ - time_t last_write_time; - uint64_t extrapad1; - }; - union { /* +72 */ - time_t last_read_time; - uint64_t extrapad2; - }; - uint8_t control_state[256]; /* +80 */ - - } SharedData; + /* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */ + typedef struct + { + uint32_t size; /* +0 */ + uint32_t last_write_index; /* +4 */ + uint32_t last_read_index; /* +8 */ + uint32_t state; /* +12 */ + uint32_t last_event; /* +16 */ + uint32_t action; /* +20 */ + int32_t brightness; /* +24 */ + int32_t hue; /* +28 */ + int32_t colour; /* +32 */ + int32_t contrast; /* +36 */ + int32_t alarm_x; /* +40 */ + int32_t alarm_y; /* +44 */ + uint8_t valid; /* +48 */ + uint8_t active; /* +49 */ + uint8_t signal; /* +50 */ + uint8_t format; /* +51 */ + uint32_t imagesize; /* +52 */ + uint32_t epadding1; /* +56 */ + uint32_t epadding2; /* +60 */ + /* + ** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038. + ** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16. + */ + union { /* +64 */ + time_t last_write_time; + uint64_t extrapad1; + }; + union { /* +72 */ + time_t last_read_time; + uint64_t extrapad2; + }; + uint8_t control_state[256]; /* +80 */ - typedef enum { TRIGGER_CANCEL, TRIGGER_ON, TRIGGER_OFF } TriggerState; - - /* sizeof(TriggerData) expected to be 560 on 32bit & and 64bit */ - typedef struct - { - uint32_t size; - uint32_t trigger_state; - uint32_t trigger_score; - uint32_t padding; - char trigger_cause[32]; - char trigger_text[256]; - char trigger_showtext[256]; - } TriggerData; + } SharedData; - /* sizeof(Snapshot) expected to be 16 bytes on 32bit and 32 bytes on 64bit */ - struct Snapshot - { - struct timeval *timestamp; - Image *image; - void* padding; - }; + typedef enum { TRIGGER_CANCEL, TRIGGER_ON, TRIGGER_OFF } TriggerState; - //TODO: Technically we can't exclude this struct when people don't have avformat as the Memory.pm module doesn't know about avformat + /* sizeof(TriggerData) expected to be 560 on 32bit & and 64bit */ + typedef struct + { + uint32_t size; + uint32_t trigger_state; + uint32_t trigger_score; + uint32_t padding; + char trigger_cause[32]; + char trigger_text[256]; + char trigger_showtext[256]; + } TriggerData; + + /* sizeof(Snapshot) expected to be 16 bytes on 32bit and 32 bytes on 64bit */ + struct Snapshot + { + struct timeval *timestamp; + Image *image; + void* padding; + }; + + //TODO: Technically we can't exclude this struct when people don't have avformat as the Memory.pm module doesn't know about avformat #if 1 - //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit - typedef struct - { - uint32_t size; - char event_file[4096]; - uint32_t recording; //bool arch dependent so use uint32 instead - //uint32_t frameNumber; - } VideoStoreData; - + //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit + typedef struct + { + uint32_t size; + char event_file[4096]; + uint32_t recording; //bool arch dependent so use uint32 instead + //uint32_t frameNumber; + } VideoStoreData; + #endif // HAVE_LIBAVFORMAT - class MonitorLink { - protected: - unsigned int id; - char name[64]; + class MonitorLink { + protected: + unsigned int id; + char name[64]; - bool connected; - time_t last_connect_time; + bool connected; + time_t last_connect_time; #if ZM_MEM_MAPPED - int map_fd; - char mem_file[PATH_MAX]; + int map_fd; + char mem_file[PATH_MAX]; #else // ZM_MEM_MAPPED - int shm_id; + int shm_id; #endif // ZM_MEM_MAPPED - off_t mem_size; - unsigned char *mem_ptr; + off_t mem_size; + unsigned char *mem_ptr; - volatile SharedData *shared_data; - volatile TriggerData *trigger_data; - volatile VideoStoreData *video_store_data; + volatile SharedData *shared_data; + volatile TriggerData *trigger_data; + volatile VideoStoreData *video_store_data; - int last_state; - int last_event; - + int last_state; + int last_event; - public: - MonitorLink( int p_id, const char *p_name ); - ~MonitorLink(); - inline int Id() const { - return( id ); - } - inline const char *Name() const { - return( name ); - } + public: + MonitorLink( int p_id, const char *p_name ); + ~MonitorLink(); - inline bool isConnected() const { - return( connected ); - } - inline time_t getLastConnectTime() const { - return( last_connect_time ); - } + inline int Id() const { + return( id ); + } + inline const char *Name() const { + return( name ); + } - bool connect(); - bool disconnect(); + inline bool isConnected() const { + return( connected ); + } + inline time_t getLastConnectTime() const { + return( last_connect_time ); + } - bool isAlarmed(); - bool inAlarm(); - bool hasAlarmed(); - }; + bool connect(); + bool disconnect(); -protected: - // These are read from the DB and thereafter remain unchanged - unsigned int id; - char name[64]; - unsigned int server_id; // Id of the Server object - unsigned int storage_id; // Id of the Storage Object, which currently will just provide a path, but in future may do more. - Function function; // What the monitor is doing - bool enabled; // Whether the monitor is enabled or asleep - unsigned int width; // Normally the same as the camera, but not if partly rotated - unsigned int height; // Normally the same as the camera, but not if partly rotated - bool v4l_multi_buffer; - unsigned int v4l_captures_per_frame; - Orientation orientation; // Whether the image has to be rotated at all - unsigned int deinterlacing; + bool isAlarmed(); + bool inAlarm(); + bool hasAlarmed(); + }; - int savejpegspref; - int videowriterpref; - std::string encoderparams; - std::vector encoderparamsvec; - bool record_audio; // Whether to store the audio that we receive + protected: + // These are read from the DB and thereafter remain unchanged + unsigned int id; + char name[64]; + unsigned int server_id; // Id of the Server object + unsigned int storage_id; // Id of the Storage Object, which currently will just provide a path, but in future may do more. + Function function; // What the monitor is doing + bool enabled; // Whether the monitor is enabled or asleep + unsigned int width; // Normally the same as the camera, but not if partly rotated + unsigned int height; // Normally the same as the camera, but not if partly rotated + bool v4l_multi_buffer; + unsigned int v4l_captures_per_frame; + Orientation orientation; // Whether the image has to be rotated at all + unsigned int deinterlacing; - int brightness; // The statically saved brightness of the camera - int contrast; // The statically saved contrast of the camera - int hue; // The statically saved hue of the camera - int colour; // The statically saved colour of the camera - char event_prefix[64]; // The prefix applied to event names as they are created - char label_format[64]; // The format of the timestamp on the images - Coord label_coord; // The coordinates of the timestamp on the images - int label_size; // Size of the timestamp on the images - int image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count - int pre_event_buffer_count; // Size of dedicated circular pre event buffer used when analysis is not performed at capturing framerate, - // value is pre_event_count + alarm_frame_count - 1 - int warmup_count; // How many images to process before looking for events - int pre_event_count; // How many images to hold and prepend to an alarm event - int post_event_count; // How many unalarmed images must occur before the alarm state is reset - int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now - int section_length; // How long events should last in continuous modes - bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor - int frame_skip; // How many frames to skip in continuous modes - int motion_frame_skip; // How many frames to skip in motion detection - double analysis_fps; // Target framerate for video analysis - unsigned int analysis_update_delay; // How long we wait before updating analysis parameters - int capture_delay; // How long we wait between capture frames - int alarm_capture_delay; // How long we wait between capture frames when in alarm state - int alarm_frame_count; // How many alarm frames are required before an event is triggered - int fps_report_interval; // How many images should be captured/processed between reporting the current FPS - int ref_blend_perc; // Percentage of new image going into reference image. - int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm. - bool track_motion; // Whether this monitor tries to track detected motion - Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected - bool embed_exif; // Whether to embed Exif data into each image frame or not + int savejpegspref; + int videowriterpref; + std::string encoderparams; + std::vector encoderparamsvec; + bool record_audio; // Whether to store the audio that we receive - double fps; - Image delta_image; - Image ref_image; - Image alarm_image; // Used in creating analysis images, will be initialized in Analysis - Image write_image; // Used when creating snapshot images + int brightness; // The statically saved brightness of the camera + int contrast; // The statically saved contrast of the camera + int hue; // The statically saved hue of the camera + int colour; // The statically saved colour of the camera + char event_prefix[64]; // The prefix applied to event names as they are created + char label_format[64]; // The format of the timestamp on the images + Coord label_coord; // The coordinates of the timestamp on the images + int label_size; // Size of the timestamp on the images + int image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count + int pre_event_buffer_count; // Size of dedicated circular pre event buffer used when analysis is not performed at capturing framerate, + // value is pre_event_count + alarm_frame_count - 1 + int warmup_count; // How many images to process before looking for events + int pre_event_count; // How many images to hold and prepend to an alarm event + int post_event_count; // How many unalarmed images must occur before the alarm state is reset + int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now + int section_length; // How long events should last in continuous modes + bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor + int frame_skip; // How many frames to skip in continuous modes + int motion_frame_skip; // How many frames to skip in motion detection + double analysis_fps; // Target framerate for video analysis + unsigned int analysis_update_delay; // How long we wait before updating analysis parameters + int capture_delay; // How long we wait between capture frames + int alarm_capture_delay; // How long we wait between capture frames when in alarm state + int alarm_frame_count; // How many alarm frames are required before an event is triggered + int fps_report_interval; // How many images should be captured/processed between reporting the current FPS + int ref_blend_perc; // Percentage of new image going into reference image. + int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm. + bool track_motion; // Whether this monitor tries to track detected motion + Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected + bool embed_exif; // Whether to embed Exif data into each image frame or not - Purpose purpose; // What this monitor has been created to do - int event_count; - int image_count; - int ready_count; - int first_alarm_count; - int last_alarm_count; - int buffer_count; - int prealarm_count; - State state; - time_t start_time; - time_t last_fps_time; - time_t auto_resume_time; - unsigned int last_motion_score; + double fps; + Image delta_image; + Image ref_image; + Image alarm_image; // Used in creating analysis images, will be initialized in Analysis + Image write_image; // Used when creating snapshot images - EventCloseMode event_close_mode; + Purpose purpose; // What this monitor has been created to do + int event_count; + int image_count; + int ready_count; + int first_alarm_count; + int last_alarm_count; + int buffer_count; + int prealarm_count; + State state; + time_t start_time; + time_t last_fps_time; + time_t auto_resume_time; + unsigned int last_motion_score; + + EventCloseMode event_close_mode; #if ZM_MEM_MAPPED - int map_fd; - char mem_file[PATH_MAX]; + int map_fd; + char mem_file[PATH_MAX]; #else // ZM_MEM_MAPPED - int shm_id; + int shm_id; #endif // ZM_MEM_MAPPED - off_t mem_size; - unsigned char *mem_ptr; - Storage *storage; + off_t mem_size; + unsigned char *mem_ptr; + Storage *storage; - SharedData *shared_data; - TriggerData *trigger_data; - VideoStoreData *video_store_data; + SharedData *shared_data; + TriggerData *trigger_data; + VideoStoreData *video_store_data; - Snapshot *image_buffer; - Snapshot next_buffer; /* Used by four field deinterlacing */ - Snapshot *pre_event_buffer; + Snapshot *image_buffer; + Snapshot next_buffer; /* Used by four field deinterlacing */ + Snapshot *pre_event_buffer; - Camera *camera; + Camera *camera; - Event *event; + Event *event; - int n_zones; - Zone **zones; + int n_zones; + Zone **zones; - struct timeval **timestamps; - Image **images; + struct timeval **timestamps; + Image **images; - const unsigned char *privacy_bitmask; + const unsigned char *privacy_bitmask; - int n_linked_monitors; - MonitorLink **linked_monitors; + int n_linked_monitors; + MonitorLink **linked_monitors; -public: -// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info. -//bool OurCheckAlarms( Zone *zone, const Image *pImage ); - Monitor( - int p_id, - const char *p_name, - unsigned int p_server_id, - unsigned int p_storage_id, - int p_function, - bool p_enabled, - const char *p_linked_monitors, - Camera *p_camera, - int p_orientation, - unsigned int p_deinterlacing, - int p_savejpegs, - int p_videowriter, - std::string p_encoderparams, - bool p_record_audio, - const char *p_event_prefix, - const char *p_label_format, - const Coord &p_label_coord, - int 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=0, - Zone *p_zones[]=0 - ); - ~Monitor(); + public: + // OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info. + //bool OurCheckAlarms( Zone *zone, const Image *pImage ); + Monitor( + int p_id, + const char *p_name, + unsigned int p_server_id, + unsigned int p_storage_id, + int p_function, + bool p_enabled, + const char *p_linked_monitors, + Camera *p_camera, + int p_orientation, + unsigned int p_deinterlacing, + int p_savejpegs, + int p_videowriter, + std::string p_encoderparams, + bool p_record_audio, + const char *p_event_prefix, + const char *p_label_format, + const Coord &p_label_coord, + int 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=0, + Zone *p_zones[]=0 + ); + ~Monitor(); - void AddZones( int p_n_zones, Zone *p_zones[] ); - void AddPrivacyBitmask( Zone *p_zones[] ); + void AddZones( int p_n_zones, Zone *p_zones[] ); + void AddPrivacyBitmask( Zone *p_zones[] ); - bool connect(); - inline int ShmValid() const { - return( shared_data->valid ); - } + bool connect(); + inline int ShmValid() const { + return( shared_data->valid ); + } - inline int Id() const { - return( id ); - } - inline const char *Name() const { - return( name ); - } - inline Storage *getStorage() { - if ( ! storage ) { - storage = new Storage( storage_id ); - } - return( storage ); - } - inline Function GetFunction() const { - return( function ); - } - inline bool Enabled() { - if ( function <= MONITOR ) - return( false ); - return( enabled ); - } - inline const char *EventPrefix() const { - return( event_prefix ); - } - inline bool Ready() { - if ( function <= MONITOR ) - return( false ); - return( image_count > ready_count ); - } - inline bool Active() { - if ( function <= MONITOR ) - return( false ); - return( enabled && shared_data->active ); - } - inline bool Exif() { - return( embed_exif ); - } + inline int Id() const { + return( id ); + } + inline const char *Name() const { + return( name ); + } + inline Storage *getStorage() { + if ( ! storage ) { + storage = new Storage( storage_id ); + } + return( storage ); + } + inline Function GetFunction() const { + return( function ); + } + inline bool Enabled() { + if ( function <= MONITOR ) + return( false ); + return( enabled ); + } + inline const char *EventPrefix() const { + return( event_prefix ); + } + inline bool Ready() { + if ( function <= MONITOR ) + return( false ); + return( image_count > ready_count ); + } + inline bool Active() { + if ( function <= MONITOR ) + return( false ); + return( enabled && shared_data->active ); + } + inline bool Exif() { + return( embed_exif ); + } - unsigned int Width() const { return width; } - unsigned int Height() const { return height; } - unsigned int Colours() const { return( camera->Colours() ); } - unsigned int SubpixelOrder() const { return( camera->SubpixelOrder() ); } + unsigned int Width() const { return width; } + unsigned int Height() const { return height; } + unsigned int Colours() const { return( camera->Colours() ); } + unsigned int SubpixelOrder() const { return( camera->SubpixelOrder() ); } - int GetOptSaveJPEGs() const { return( savejpegspref ); } - int GetOptVideoWriter() const { return( videowriterpref ); } - const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } - - State GetState() const; - int GetImage( int index=-1, int scale=100 ); - struct timeval GetTimestamp( int index=-1 ) const; - void UpdateAdaptiveSkip(); - useconds_t GetAnalysisRate(); - unsigned int GetAnalysisUpdateDelay() const { return( analysis_update_delay ); } - int GetCaptureDelay() const { return( capture_delay ); } - int GetAlarmCaptureDelay() const { return( alarm_capture_delay ); } - unsigned int GetLastReadIndex() const; - unsigned int GetLastWriteIndex() const; - unsigned int GetLastEvent() const; - double GetFPS() const; - void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" ); - void ForceAlarmOff(); - void CancelForced(); - TriggerState GetTriggerState() const { return( (TriggerState)(trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL )); } + int GetOptSaveJPEGs() const { return( savejpegspref ); } + int GetOptVideoWriter() const { return( videowriterpref ); } + const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } - void actionReload(); - void actionEnable(); - void actionDisable(); - void actionSuspend(); - void actionResume(); + State GetState() const; + int GetImage( int index=-1, int scale=100 ); + struct timeval GetTimestamp( int index=-1 ) const; + void UpdateAdaptiveSkip(); + useconds_t GetAnalysisRate(); + unsigned int GetAnalysisUpdateDelay() const { return( analysis_update_delay ); } + int GetCaptureDelay() const { return( capture_delay ); } + int GetAlarmCaptureDelay() const { return( alarm_capture_delay ); } + unsigned int GetLastReadIndex() const; + unsigned int GetLastWriteIndex() const; + unsigned int GetLastEvent() const; + double GetFPS() const; + void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" ); + void ForceAlarmOff(); + void CancelForced(); + TriggerState GetTriggerState() const { return( (TriggerState)(trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL )); } - int actionBrightness( int p_brightness=-1 ); - int actionHue( int p_hue=-1 ); - int actionColour( int p_colour=-1 ); - int actionContrast( int p_contrast=-1 ); + void actionReload(); + void actionEnable(); + void actionDisable(); + void actionSuspend(); + void actionResume(); - inline int PrimeCapture() { - return( camera->PrimeCapture() ); - } - inline int PreCapture() { - return( camera->PreCapture() ); - } - int Capture(); - int PostCapture() { - return( camera->PostCapture() ); - } + int actionBrightness( int p_brightness=-1 ); + int actionHue( int p_hue=-1 ); + int actionColour( int p_colour=-1 ); + int actionContrast( int p_contrast=-1 ); - unsigned int DetectMotion( const Image &comp_image, Event::StringSet &zoneSet ); - // DetectBlack seems to be unused. Check it on zm_monitor.cpp for more info. - //unsigned int DetectBlack( const Image &comp_image, Event::StringSet &zoneSet ); - bool CheckSignal( const Image *image ); - bool Analyse(); - void DumpImage( Image *dump_image ) const; - void TimestampImage( Image *ts_image, const struct timeval *ts_time ) const; - bool closeEvent(); + inline int PrimeCapture() { + return( camera->PrimeCapture() ); + } + inline int PreCapture() { + return( camera->PreCapture() ); + } + int Capture(); + int PostCapture() { + return( camera->PostCapture() ); + } - void Reload(); - void ReloadZones(); - void ReloadLinkedMonitors( const char * ); + unsigned int DetectMotion( const Image &comp_image, Event::StringSet &zoneSet ); + // DetectBlack seems to be unused. Check it on zm_monitor.cpp for more info. + //unsigned int DetectBlack( const Image &comp_image, Event::StringSet &zoneSet ); + bool CheckSignal( const Image *image ); + bool Analyse(); + void DumpImage( Image *dump_image ) const; + void TimestampImage( Image *ts_image, const struct timeval *ts_time ) const; + bool closeEvent(); - bool DumpSettings( char *output, bool verbose ); - void DumpZoneImage( const char *zone_string=0 ); + void Reload(); + void ReloadZones(); + void ReloadLinkedMonitors( const char * ); + + bool DumpSettings( char *output, bool verbose ); + void DumpZoneImage( const char *zone_string=0 ); #if ZM_HAS_V4L - static int LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ); + static int LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ); #endif // ZM_HAS_V4L - static int LoadRemoteMonitors( const char *protocol, const char *host, const char*port, const char*path, Monitor **&monitors, Purpose purpose ); - static int LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ); + static int LoadRemoteMonitors( const char *protocol, const char *host, const char*port, const char*path, Monitor **&monitors, Purpose purpose ); + static int LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ); #if HAVE_LIBAVFORMAT - static int LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ); + static int LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ); #endif // HAVE_LIBAVFORMAT - static Monitor *Load( unsigned int id, bool load_zones, Purpose purpose ); - //void writeStreamImage( Image *image, struct timeval *timestamp, int scale, int mag, int x, int y ); - //void StreamImages( int scale=100, int maxfps=10, time_t ttl=0, int msq_id=0 ); - //void StreamImagesRaw( int scale=100, int maxfps=10, time_t ttl=0 ); - //void StreamImagesZip( int scale=100, int maxfps=10, time_t ttl=0 ); - void SingleImage( int scale=100 ); - void SingleImageRaw( int scale=100 ); - void SingleImageZip( int scale=100 ); + static Monitor *Load( unsigned int id, bool load_zones, Purpose purpose ); + //void writeStreamImage( Image *image, struct timeval *timestamp, int scale, int mag, int x, int y ); + //void StreamImages( int scale=100, int maxfps=10, time_t ttl=0, int msq_id=0 ); + //void StreamImagesRaw( int scale=100, int maxfps=10, time_t ttl=0 ); + //void StreamImagesZip( int scale=100, int maxfps=10, time_t ttl=0 ); + void SingleImage( int scale=100 ); + void SingleImageRaw( int scale=100 ); + void SingleImageZip( int scale=100 ); #if HAVE_LIBAVCODEC - //void StreamMpeg( const char *format, int scale=100, int maxfps=10, int bitrate=100000 ); + //void StreamMpeg( const char *format, int scale=100, int maxfps=10, int bitrate=100000 ); #endif // HAVE_LIBAVCODEC }; #define MOD_ADD( var, delta, limit ) (((var)+(limit)+(delta))%(limit)) class MonitorStream : public StreamBase { -protected: - typedef struct SwapImage { - bool valid; - struct timeval timestamp; - char file_name[PATH_MAX]; - } SwapImage; + protected: + typedef struct SwapImage { + bool valid; + struct timeval timestamp; + char file_name[PATH_MAX]; + } SwapImage; -private: - SwapImage *temp_image_buffer; - int temp_image_buffer_count; - int temp_read_index; - int temp_write_index; + private: + SwapImage *temp_image_buffer; + int temp_image_buffer_count; + int temp_read_index; + int temp_write_index; -protected: - time_t ttl; + protected: + time_t ttl; -protected: - int playback_buffer; - bool delayed; + protected: + int playback_buffer; + bool delayed; - int frame_count; + int frame_count; -protected: - bool checkSwapPath( const char *path, bool create_path ); + protected: + bool checkSwapPath( const char *path, bool create_path ); - bool sendFrame( const char *filepath, struct timeval *timestamp ); - bool sendFrame( Image *image, struct timeval *timestamp ); - void processCommand( const CmdMsg *msg ); + bool sendFrame( const char *filepath, struct timeval *timestamp ); + bool sendFrame( Image *image, struct timeval *timestamp ); + void processCommand( const CmdMsg *msg ); -public: - MonitorStream() : playback_buffer( 0 ), delayed( false ), frame_count( 0 ) { - } - void setStreamBuffer( int p_playback_buffer ) { - playback_buffer = p_playback_buffer; - } - void setStreamTTL( time_t p_ttl ) { - ttl = p_ttl; - } - bool setStreamStart( int monitor_id ) { - return loadMonitor( monitor_id ); - } - void runStream(); + public: + MonitorStream() : playback_buffer( 0 ), delayed( false ), frame_count( 0 ) { + } + void setStreamBuffer( int p_playback_buffer ) { + playback_buffer = p_playback_buffer; + } + void setStreamTTL( time_t p_ttl ) { + ttl = p_ttl; + } + bool setStreamStart( int monitor_id ) { + return loadMonitor( monitor_id ); + } + void runStream(); }; #endif // ZM_MONITOR_H