diff --git a/configure b/configure index b6aaabe2e..3688c5a7e 100755 --- a/configure +++ b/configure @@ -1500,7 +1500,7 @@ fi # Define the identity of the package. PACKAGE=zm - VERSION=1.18.1-ms + VERSION=1.19.0 cat >>confdefs.h <<_ACEOF diff --git a/configure.in b/configure.in index a808d8cda..754f563b0 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ AC_INIT(src/zm.h) -AM_INIT_AUTOMAKE(zm,1.18.1-ms) +AM_INIT_AUTOMAKE(zm,1.19.0) AM_CONFIG_HEADER(config.h) AC_ARG_WITH(mysql, diff --git a/db/Makefile.am b/db/Makefile.am index 60a18a612..e003e8229 100644 --- a/db/Makefile.am +++ b/db/Makefile.am @@ -14,4 +14,5 @@ EXTRA_DIST = \ zmalter-0.9.16.sql \ zmalter-1.17.1.sql \ zmalter-1.17.2.sql \ - zmalter-1.18.0.sql + zmalter-1.18.0.sql \ + zmalter-1.18.1.sql diff --git a/db/Makefile.in b/db/Makefile.in index 57037ca15..2ec89bba2 100644 --- a/db/Makefile.in +++ b/db/Makefile.in @@ -104,7 +104,8 @@ EXTRA_DIST = \ zmalter-0.9.16.sql \ zmalter-1.17.1.sql \ zmalter-1.17.2.sql \ - zmalter-1.18.0.sql + zmalter-1.18.0.sql \ + zmalter-1.18.1.sql subdir = db mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs diff --git a/db/zmalter-1.18.1.sql b/db/zmalter-1.18.1.sql new file mode 100644 index 000000000..9267314ad --- /dev/null +++ b/db/zmalter-1.18.1.sql @@ -0,0 +1,17 @@ +-- +-- This updates a 1.18.1 database to 1.18.2 +-- +-- Make changes to Zones table +-- +alter table Frames add column Type enum('Normal','Bulk','Alarm') NOT NULL default 'Normal' after FrameId; +update Frames set Type = 'Alarm' where AlarmFrame = 1; +alter table Frames drop column AlarmFrame; +-- +-- These are optional, but we might as well +-- +optimize table Frames; +optimize table Events; +optimize table Filters; +optimize table Zones; +optimize table Monitors; +optimize table Stats; diff --git a/db/zmschema.sql.z b/db/zmschema.sql.z index e0dda0338..0073d5f5a 100644 --- a/db/zmschema.sql.z +++ b/db/zmschema.sql.z @@ -86,7 +86,7 @@ CREATE TABLE Frames ( Id int(10) unsigned NOT NULL auto_increment, EventId int(10) unsigned NOT NULL default '0', FrameId int(10) unsigned NOT NULL default '0', - AlarmFrame tinyint(4) NOT NULL default '0', + Type enum('Normal','Bulk','Alarm') NOT NULL default 'Normal', TimeStamp timestamp(14) NOT NULL, Delta decimal(8,2) NOT NULL default '0.00', Score smallint(5) unsigned NOT NULL default '0', diff --git a/scripts/zmfilter.pl.z b/scripts/zmfilter.pl.z index 5cf786eec..9b0d0fa74 100755 --- a/scripts/zmfilter.pl.z +++ b/scripts/zmfilter.pl.z @@ -663,29 +663,24 @@ sub substituteTags # Do we need the image information too? my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM)%/; - my @frames = (); my $first_alarm_frame; my $max_alarm_frame; my $max_alarm_score = 0; if ( $need_images ) { - my $sql = "select * from Frames where EventId = ? order by FrameId"; + my $sql = "select * from Frames where EventId = ? and Type = 'Alarm' order by FrameId"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( $event->{Id} ) or die( "Can't execute: ".$sth->errstr() ); while( my $frame = $sth->fetchrow_hashref() ) { - push( @frames, $frame ); - if ( $frame->{AlarmFrame} ) + if ( !$first_alarm_frame ) { - if ( !$first_alarm_frame ) - { - $first_alarm_frame = $frame; - } - if ( $frame->{Score} > $max_alarm_score ) - { - $max_alarm_frame = $frame; - $max_alarm_score = $frame->{Score}; - } + $first_alarm_frame = $frame; + } + if ( $frame->{Score} > $max_alarm_score ) + { + $max_alarm_frame = $frame; + $max_alarm_score = $frame->{Score}; } } $sth->finish(); diff --git a/src/zm_event.cpp b/src/zm_event.cpp index df32c3748..4d1bd0c29 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -34,6 +34,7 @@ bool Event::initialised = false; bool Event::timestamp_on_capture; +bool Event::bulk_frame_interval; Event::Event( Monitor *p_monitor, struct timeval p_start_time ) : monitor( p_monitor ), start_time( p_start_time ) { @@ -267,7 +268,7 @@ void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps } } -void Event::AddFrame( Image *image, struct timeval timestamp, unsigned int score, Image *alarm_image ) +void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *alarm_image ) { frames++; @@ -280,16 +281,23 @@ void Event::AddFrame( Image *image, struct timeval timestamp, unsigned int score struct DeltaTimeval delta_time; DELTA_TIMEVAL( delta_time, timestamp, start_time, DT_PREC_2 ); - Debug( 1, ( "Adding frame %d to DB", frames )); - static char sql[BUFSIZ]; - sprintf( sql, "insert into Frames ( EventId, FrameId, AlarmFrame, Delta, Score ) values ( %d, %d, %d, %s%ld.%02ld, %d )", id, frames, score>0, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score ); - if ( mysql_query( &dbconn, sql ) ) + bool db_frame = score>=0 || !((frames-1)%bulk_frame_interval); + + if ( db_frame ) { - Error(( "Can't insert frame: %s", mysql_error( &dbconn ) )); - exit( mysql_errno( &dbconn ) ); + const char *frame_type = score>0?"Normal":(score<0?"Bulk":"Alarm"); + + Debug( 1, ( "Adding frame %d to DB", frames )); + static char sql[BUFSIZ]; + sprintf( sql, "insert into Frames ( EventId, FrameId, AlarmFrame, Delta, Score ) values ( %d, %d, '%s', %s%ld.%02ld, %d )", id, frames, frame_type, 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 ) ); + } } - if ( score ) + if ( score > 0 ) { end_time = timestamp; diff --git a/src/zm_event.h b/src/zm_event.h index c5285eb3f..9d6c0f8c0 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -44,6 +44,7 @@ class Event protected: static bool initialised; static bool timestamp_on_capture; + static bool bulk_frame_interval; protected: static int sd; @@ -65,6 +66,7 @@ protected: initialised = true; timestamp_on_capture = (bool)config.Item( ZM_TIMESTAMP_ON_CAPTURE ); + bulk_frame_interval = (bool)config.Item( ZM_BULK_FRAME_INTERVAL ); } public: @@ -87,7 +89,7 @@ public: bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false ); void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); - void AddFrame( Image *image, struct timeval timestamp, unsigned int score=0, Image *alarm_frame=NULL ); + void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ); static void StreamEvent( int event_id, int rate=100, int scale=100 ); #if HAVE_LIBAVCODEC diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index fe268317d..2d55a005e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -34,6 +34,7 @@ bool Monitor::opt_adaptive_skip; bool Monitor::create_analysis_images; bool Monitor::blend_alarmed_images; bool Monitor::timestamp_on_capture; +bool Monitor::bulk_frame_interval; Monitor::Monitor( int p_id, @@ -779,7 +780,14 @@ bool Monitor::Analyse() { if ( !(image_count%(frame_skip+1)) ) { - event->AddFrame( snap_image, *timestamp ); + if ( bulk_frame_interval > 1 ) + { + event->AddFrame( snap_image, *timestamp, -1 ); + } + else + { + event->AddFrame( snap_image, *timestamp ); + } } } } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index ce3792739..8a7b2e7b7 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -70,6 +70,7 @@ protected: static bool create_analysis_images; static bool blend_alarmed_images; static bool timestamp_on_capture; + static bool bulk_frame_interval; protected: // These are read from the DB and thereafter remain unchanged @@ -152,6 +153,7 @@ protected: create_analysis_images = (bool)config.Item( ZM_CREATE_ANALYSIS_IMAGES ); blend_alarmed_images = (bool)config.Item( ZM_BLEND_ALARMED_IMAGES ); timestamp_on_capture = (bool)config.Item( ZM_TIMESTAMP_ON_CAPTURE ); + bulk_frame_interval = (bool)config.Item( ZM_BULK_FRAME_INTERVAL ); } public: diff --git a/web/zm_html_view_event.php b/web/zm_html_view_event.php index 841f07cba..54b24bfb1 100644 --- a/web/zm_html_view_event.php +++ b/web/zm_html_view_event.php @@ -314,12 +314,31 @@ AutoStart=true> } else { - $sql = "select * from Frames where EventID = '$eid' order by Id"; if ( $paged && !empty($page) ) - $sql .= " limit ".(($page-1)*$frames_per_page).", ".$frames_per_page; + { + $lo_frame_id = (($page-1)*$frames_per_page)+1; + $hi_frame_id = min( $page*$frames_per_page, $event['Frames'] ); + } + else + { + $lo_frame = 1; + $hi_frame = $event['Frames']; + } + $sql = "select * from Frames where EventID = '$eid'"; + if ( $paged && !empty($page) ) + $sql .= " and FrameId between $lo_frame_id and $hi_frame_id"; + $sql .= "order by FrameId"; $result = mysql_query( $sql ); if ( !$result ) die( mysql_error() ); + $alarm_frames = array(); + while( $row = mysql_fetch_assoc( $result ) ) + { + if ( $row['Type'] == 'Alarm' ) + { + $alarm_frames[$row['FrameId']] = $row; + } + } ?> @@ -330,9 +349,8 @@ else $thumb_width = $event['Width']/4; $thumb_height = $event['Height']/4; $event_path = ZM_DIR_EVENTS.'/'.$event['MonitorName'].'/'.$event['Id']; - while( $row = mysql_fetch_assoc( $result ) ) + for ( $frame_id = $lo_frame; $frame_id <= $hi_frame_id; $frame_id++ ) { - $frame_id = $row['FrameId']; $image_path = sprintf( "%s/%03d-capture.jpg", $event_path, $frame_id ); $capt_image = $image_path; @@ -364,9 +382,10 @@ else exec( $command ); } } - $img_class = $row['AlarmFrame']?"alarm":"normal"; + $alarm_frame = $alarm_frames[$frame_id]; + $img_class = $alarm_frame?"alarm":"normal"; ?> - + @@ -89,7 +86,7 @@ function deleteEvent()
<?= $frame_id ?>/<?= $row['Score'] ?><?= $frame_id ?>/<?= $alarm_frame['Score'] ?>
diff --git a/web/zm_html_view_frames.php b/web/zm_html_view_frames.php index f07362e35..3f7db3c2b 100644 --- a/web/zm_html_view_frames.php +++ b/web/zm_html_view_frames.php @@ -23,13 +23,21 @@ if ( !canView( 'Events' ) ) $view = "error"; return; } -$result = mysql_query( "select F.*,unix_timestamp(F.TimeStamp) as UnixTimeStamp,E.*,M.Name as MonitorName,M.Width,M.Height from Frames as F left join Events as E on F.EventId = E.Id left join Monitors as M on E.MonitorId = M.Id where F.EventId = '$eid' order by F.FrameId" ); +$sql = "select E.*,M.Name as MonitorName,M.Width,M.Height from Events as E inner join Monitors as M on E.MonitorId = M.Id where E.Id = '$eid'"; +$result = mysql_query( $sql ); +if ( !$result ) + die( mysql_error() ); +$event = mysql_fetch_assoc( $result ); + +$sql = "select * from Frames where EventID = '$eid' order by FrameId"; +$result = mysql_query( $sql ); if ( !$result ) die( mysql_error() ); while ( $row = mysql_fetch_assoc( $result ) ) { $frames[] = $row; } + ?> @@ -65,14 +73,16 @@ if ( count($frames) ) { foreach ( $frames as $frame ) { + $alarm_frame = $frame['Type']=='Alarm'; + $bgcolor = $alarm_frame?'#FA8072':($frame['Type']=='Bulk'?'#CCCCCC':'#FFFFFF'); ?> - + - + diff --git a/zmconfig.pl.in b/zmconfig.pl.in index 2e073852c..79525ddf2 100755 --- a/zmconfig.pl.in +++ b/zmconfig.pl.in @@ -810,6 +810,14 @@ my @options = type => $types{integer}, category => 'video', }, + { + name => "ZM_BULK_FRAME_INTERVAL", + default => "100", + description => "How often a bulk frame should be written to the database", + help => "Traditionally ZoneMinder writes an entry into the Frames database table for each frame that is captured and saved. This works well in motion detection scenarios but when in a DVR situation ('Record' or 'Mocord' mode) this results in a huge number of frame writes and a lot of database and disk bandwidth for very little additional information. Setting this to a non-zero value will enabled ZoneMinder to group these non-alarm frames into one 'bulk' frame entry which saves a lot of bandwidth and space. The only disadvantage of this is that timing information for individual frames is lost but in constant frame rate situations this is usually not significant. This setting is ignored in Modect mode and individual frames are still written if an alarm occurs in Mocord mode also.", + type => $types{integer}, + category => 'video', + }, { name => "ZM_RECORD_EVENT_STATS", default => "yes",
- + ()