diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 6c4750845..bb0923c99 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -31,12 +31,16 @@ use warnings; require ZoneMinder::Base; require ZoneMinder::Object; require ZoneMinder::Storage; +require ZoneMinder::Frame; require Date::Manip; require File::Find; require File::Path; require File::Copy; require File::Basename; require Number::Bytes::Human; +require Date::Parse; +require POSIX; +use Date::Format qw(time2str); #our @ISA = qw(ZoneMinder::Object); use parent qw(ZoneMinder::Object); @@ -50,7 +54,6 @@ use parent qw(ZoneMinder::Object); use ZoneMinder::Config qw(:all); use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); -require Date::Parse; use vars qw/ $table $primary_key %fields $serial @identified_by %defaults/; $table = 'Events'; @@ -96,7 +99,6 @@ $serial = $primary_key = 'Id'; Executed => '0', ); -use POSIX; sub Time { if ( @_ > 1 ) { @@ -158,7 +160,7 @@ sub RelativePath { if ( $event->Time() ) { $$event{RelativePath} = join('/', $event->{MonitorId}, - strftime( '%y/%m/%d/%H/%M/%S', + POSIX::strftime( '%y/%m/%d/%H/%M/%S', localtime($event->Time()) ), ); @@ -170,7 +172,7 @@ sub RelativePath { if ( $event->Time() ) { $$event{RelativePath} = join('/', $event->{MonitorId}, - strftime('%Y-%m-%d', localtime($event->Time())), + POSIX::strftime('%Y-%m-%d', localtime($event->Time())), $event->{Id}, ); } else { @@ -198,7 +200,7 @@ sub LinkPath { if ( $event->Time() ) { $$event{LinkPath} = join('/', $event->{MonitorId}, - strftime( '%y/%m/%d', + POSIX::strftime( '%y/%m/%d', localtime($event->Time()) ), '.'.$$event{Id} @@ -678,9 +680,19 @@ sub recover_timestamps { closedir(DIR); my @mp4_files = grep( /^\d+\-video\.mp4$/, @contents); - my @capture_jpgs = grep( /^\d+\-capture\.jpg$/, @contents); + if ( @mp4_files ) { + $$Event{DefaultVideo} = $mp4_files[0]; + } + my @analyse_jpgs = grep( /^\d+\-analyse\.jpg$/, @contents); + if ( @analyse_jpgs ) { + $$Event{Save_JPEGs} |= 2; + } + + my @capture_jpgs = grep( /^\d+\-capture\.jpg$/, @contents); if ( @capture_jpgs ) { + $$Event{Frames} = scalar @capture_jpgs; + $$Event{Save_JPEGs} |= 1; # can get start and end times from stat'ing first and last jpg @capture_jpgs = sort { $a cmp $b } @capture_jpgs; my $first_file = "$path/$capture_jpgs[0]"; @@ -696,6 +708,25 @@ sub recover_timestamps { $Event->StartTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp) ); $Event->EndTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $last_timestamp) ); Debug("From capture Jpegs have duration $duration = $last_timestamp - $first_timestamp : $$Event{StartTime} to $$Event{EndTime}"); + $ZoneMinder::Database::dbh->begin_work(); + foreach my $jpg ( @capture_jpgs ) { + my ( $id ) = $jpg =~ /^(\d+)\-capture\.jpg$/; + + if ( ! ZoneMinder::Frame->find_one( EventId=>$$Event{Id}, FrameId=>$id ) ) { + my $file = "$path/$jpg"; + ( $file ) = $file =~ /^(.*)$/; + my $timestamp = (stat($file))[9]; + my $Frame = new ZoneMinder::Frame(); + $Frame->save({ + EventId=>$$Event{Id}, FrameId=>$id, + TimeStamp=>Date::Format::time2str('%Y-%m-%d %H:%M:%S',$timestamp), + Delta => $timestamp - $first_timestamp, + Type=>'Normal', + Score=>0, + }); + } + } + $ZoneMinder::Database::dbh->commit(); } elsif ( @mp4_files ) { my $file = "$path/$mp4_files[0]"; ( $file ) = $file =~ /^(.*)$/; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index f1a72c8cf..73ebc2d10 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -30,6 +30,7 @@ use warnings; require ZoneMinder::Base; require Date::Manip; +require POSIX; use parent qw(ZoneMinder::Object); @@ -48,8 +49,6 @@ use ZoneMinder::Database qw(:all); require ZoneMinder::Storage; require ZoneMinder::Server; -use POSIX; - sub Name { if ( @_ > 1 ) { $_[0]{Name} = $_[1]; @@ -435,7 +434,7 @@ sub DateTimeToSQL { Error( "Unable to parse date string '$dt_str'\n" ); return( undef ); } - return( strftime( "%Y-%m-%d %H:%M:%S", localtime( $dt_val ) ) ); + return( POSIX::strftime( "%Y-%m-%d %H:%M:%S", localtime( $dt_val ) ) ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 6d7ecc660..d6c90d6aa 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -91,7 +91,7 @@ use ZoneMinder::Config qw(:all); use DBI; use Carp; -use POSIX; +require POSIX; use IO::Handle; use Data::Dumper; use Time::HiRes qw/gettimeofday/; @@ -539,7 +539,7 @@ sub logPrint { if ( $level <= $this->{fileLevel} or $level <= $this->{termLevel} ) { my $message = sprintf( '%s.%06d %s[%d].%s [%s:%d] [%s]' - , strftime('%x %H:%M:%S', localtime($seconds)) + , POSIX::strftime('%x %H:%M:%S', localtime($seconds)) , $microseconds , $this->{id} , $$ diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index faac440ac..a3f08a402 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -341,7 +341,7 @@ $log->debug("No serial") if $debug; } # end if } # end if ZoneMinder::Database::end_transaction( $local_dbh, $ac ); - $self->load(); + #$self->load(); #if ( $$fields{id} ) { #if ( ! $ZoneMinder::Object::cache{$type}{$$self{id}} ) { #$ZoneMinder::Object::cache{$type}{$$self{id}} = $self; diff --git a/scripts/zmrecover.pl.in b/scripts/zmrecover.pl.in index 9b0f589ff..5d1942ce2 100644 --- a/scripts/zmrecover.pl.in +++ b/scripts/zmrecover.pl.in @@ -25,7 +25,6 @@ use POSIX; use File::Find; use Time::HiRes qw/gettimeofday/; use Getopt::Long; -use Date::Format; use autouse 'Pod::Usage'=>qw(pod2usage); use constant ZM_RECOVER_PID => '@ZM_RUNDIR@/zmrecover.pid'; @@ -231,7 +230,6 @@ Debug("@Monitors"); $Event->Width( $Monitor->Width() ); $Event->Height( $Monitor->Height() ); $Event->Orientation( $Monitor->Orientation() ); - $Event->recover_timestamps(); $Event->save({}, 1); @@ -343,18 +341,18 @@ Debug("@Monitors"); $$Event{Id} = $event_id; $$Event{Path} = join('/', $Storage->Path(), $event_dir ); Debug("Have event $$Event{Id} at $$Event{Path}"); - $$Event{Scheme} = 'Medium'; - $$Event{RelativePath} = $event_dir; - $$Event{Name} = "Event $event_id recovered"; - $Event->MonitorId( $monitor_dir ); - $Event->Width( $Monitor->Width() ); - $Event->Height( $Monitor->Height() ); - $Event->Orientation( $Monitor->Orientation() ); - $Event->StorageId( $Storage->Id() ); - $Event->recover_timestamps(); if ( confirm() ) { + $$Event{Scheme} = 'Medium'; + $$Event{RelativePath} = $event_dir; + $$Event{Name} = "Event $event_id recovered"; + $Event->MonitorId( $monitor_dir ); + $Event->Width( $Monitor->Width() ); + $Event->Height( $Monitor->Height() ); + $Event->Orientation( $Monitor->Orientation() ); + $Event->StorageId( $Storage->Id() ); + $Event->recover_timestamps(); $Event->save({}, 1); - Debug("Event resurrected as " . $Event->to_string() ); + Debug("Event resurrected as " . $Event->to_string() ); } } # end foreach event } # end search for Medium @@ -380,17 +378,19 @@ Debug("@Monitors"); $$Event{Id} = $event; $$Event{Path} = join('/', $Storage->Path(), $event ); Debug("Have event $$Event{Id} at $$Event{Path}"); - $$Event{Scheme} = 'Shallow'; - $$Event{Name} = "Event $event recovered"; - #$$Event{Path} = $event_path; - $Event->MonitorId( $monitor_dir ); - $Event->Width( $Monitor->Width() ); - $Event->Height( $Monitor->Height() ); - $Event->Orientation( $Monitor->Orientation() ); - $Event->StorageId( $Storage->Id() ); - $Event->recover_timestamps(); - $Event->save({}, 1); - Debug("Event resurrected as " . $Event->to_string() ); + if ( confirm() ) { + $$Event{Scheme} = 'Shallow'; + $$Event{Name} = "Event $event recovered"; + #$$Event{Path} = $event_path; + $Event->MonitorId( $monitor_dir ); + $Event->Width( $Monitor->Width() ); + $Event->Height( $Monitor->Height() ); + $Event->Orientation( $Monitor->Orientation() ); + $Event->StorageId( $Storage->Id() ); + $Event->recover_timestamps(); + $Event->save({}, 1); + Debug("Event resurrected as " . $Event->to_string() ); + } } # end foreach event chdir( $Storage->Path() ); } # end foreach monitor diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 9f7eae4ec..23edf3463 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -109,7 +109,10 @@ bool EventStream::loadInitialEventData( uint64_t init_event_id, unsigned int ini bool EventStream::loadEventData(uint64_t event_id) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %" PRIu64, event_id); + snprintf(sql, sizeof(sql), + "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, " + "(SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, " + "DefaultVideo, Scheme, SaveJPEGs FROM Events WHERE Id = %" PRIu64, event_id); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); @@ -151,6 +154,7 @@ bool EventStream::loadEventData(uint64_t event_id) { } else { event_data->scheme = Storage::SHALLOW; } + event_data->SaveJPEGs = dbrow[7] == NULL ? 0 : atoi(dbrow[7]); mysql_free_result( result ); Storage * storage = new Storage(event_data->storage_id); @@ -241,6 +245,7 @@ bool EventStream::loadEventData(uint64_t event_id) { if ( event_data->video_file[0] ) { char filepath[PATH_MAX]; snprintf(filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file); + Debug(1, "Loading video file from %s", filepath); ffmpeg_input = new FFmpeg_Input(); if ( 0 > ffmpeg_input->Open( filepath ) ) { Warning("Unable to open ffmpeg_input %s/%s", event_data->path, event_data->video_file); @@ -570,14 +575,17 @@ bool EventStream::sendFrame( int delta_us ) { // This needs to be abstracted. If we are saving jpgs, then load the capture file. If we are only saving analysis frames, then send that. // // This is also wrong, need to have this info stored in the event! FIXME - if ( monitor->GetOptSaveJPEGs() & 1 ) { + if ( event_data->SaveJPEGs & 1 ) { snprintf( filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id ); - } else if ( monitor->GetOptSaveJPEGs() & 2 ) { + } else if ( event_data->SaveJPEGs & 2 ) { snprintf( filepath, sizeof(filepath), staticConfig.analyse_file_format, event_data->path, curr_frame_id ); if ( stat( filepath, &filestat ) < 0 ) { Debug(1, "analyze file %s not found will try to stream from other", filepath); snprintf( filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id ); - filepath[0] = 0; + if ( stat( filepath, &filestat ) < 0 ) { + Debug(1, "capture file %s not found either", filepath); + filepath[0] = 0; + } } } else if ( ! ffmpeg_input ) { diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index 90200df65..a6ca99aee 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -65,6 +65,7 @@ class EventStream : public StreamBase { FrameData *frames; char video_file[PATH_MAX]; Storage::Schemes scheme; + int SaveJPEGs; }; protected: