Merge branch 'master' into zma_to_thread

This commit is contained in:
Isaac Connor 2020-07-22 13:14:40 -04:00
commit 3641797500
10 changed files with 147 additions and 163 deletions

View File

@ -20,18 +20,16 @@ sub START {
sub Subscribe { sub Subscribe {
my ($self, $body, $header) = @_; my ($self, $body, $header) = @_;
die "Subscribe must be called as object method (\$self is <$self>)" if not blessed($self); die "Subscribe must be called as object method (\$self is <$self>)" if not blessed($self);
#print " proxy/lib/WSNotification/Interfaces/WSBaseNotificationSender/NotificationProducerPort.pm Subscribe\n";
return $self->SUPER::call({ return $self->SUPER::call({
operation => 'Subscribe', operation => 'Subscribe',
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/Subscribe', soap_action => 'http://docs.oasis-open.org/wsn/bw-2/Subscribe',
style => 'document', style => 'document',
body => { body => {
use => 'literal',
'use' => 'literal',
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/', namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
encodingStyle => '', encodingStyle => '',
parts => [qw( WSNotification::Elements::Subscribe )], parts => [qw( WSNotification::Elements::Subscribe )],
}, },
header => { header => {
@ -42,7 +40,6 @@ sub Subscribe {
}, $body, $header); }, $body, $header);
} }
sub GetCurrentMessage { sub GetCurrentMessage {
my ($self, $body, $header) = @_; my ($self, $body, $header) = @_;
die "GetCurrentMessage must be called as object method (\$self is <$self>)" if not blessed($self); die "GetCurrentMessage must be called as object method (\$self is <$self>)" if not blessed($self);
@ -51,9 +48,7 @@ sub GetCurrentMessage {
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/GetCurrentMessage', soap_action => 'http://docs.oasis-open.org/wsn/bw-2/GetCurrentMessage',
style => 'document', style => 'document',
body => { body => {
use => 'literal',
'use' => 'literal',
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/', namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
encodingStyle => '', encodingStyle => '',
parts => [qw( WSNotification::Elements::GetCurrentMessage )], parts => [qw( WSNotification::Elements::GetCurrentMessage )],
@ -68,13 +63,7 @@ sub GetCurrentMessage {
}, $body, $header); }, $body, $header);
} }
1; 1;
__END__ __END__
=pod =pod

View File

@ -91,7 +91,7 @@ Event::Event(
"INSERT INTO `Events` " "INSERT INTO `Events` "
"( `MonitorId`, `StorageId`, `Name`, `StartTime`, `Width`, `Height`, `Cause`, `Notes`, `StateId`, `Orientation`, `Videoed`, `DefaultVideo`, `SaveJPEGs`, `Scheme` )" "( `MonitorId`, `StorageId`, `Name`, `StartTime`, `Width`, `Height`, `Cause`, `Notes`, `StateId`, `Orientation`, `Videoed`, `DefaultVideo`, `SaveJPEGs`, `Scheme` )"
" VALUES " " VALUES "
"( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d, '%s' )", "( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '%s', %d, '%s' )",
monitor->Id(), monitor->Id(),
storage->Id(), storage->Id(),
start_time.tv_sec, start_time.tv_sec,
@ -102,6 +102,7 @@ Event::Event(
state_id, state_id,
monitor->getOrientation(), monitor->getOrientation(),
( monitor->GetOptVideoWriter() != 0 ? 1 : 0 ), ( monitor->GetOptVideoWriter() != 0 ? 1 : 0 ),
( monitor->GetOptVideoWriter() != 0 ? "video.mp4" : "" ),
monitor->GetOptSaveJPEGs(), monitor->GetOptSaveJPEGs(),
storage->SchemeString().c_str() storage->SchemeString().c_str()
); );
@ -113,23 +114,7 @@ Event::Event(
return; return;
} }
id = mysql_insert_id(&dbconn); id = mysql_insert_id(&dbconn);
//
/* Update event record with DefaultVideo name if possible so image.php can extract frames
if needed, while recording is in progress */
if ( monitor->GetOptVideoWriter() != 0 ) {
video_name[0] = 0;
snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s", id, "video.mp4");
Debug(1, "Updating inserted event with DefaultVideo=%s",video_name);
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name,id);
if ( mysql_query(&dbconn, sql) ) {
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
db_mutex.unlock();
return;
}
} else {
Debug (1, "GetOptVideoWriter() returned 0, not updating DefaultVideo");
}
db_mutex.unlock(); db_mutex.unlock();
if ( untimedEvent ) { if ( untimedEvent ) {
Warning("Event %d has zero time, setting to current", id); Warning("Event %d has zero time, setting to current", id);
@ -143,12 +128,13 @@ Event::Event(
alarm_frame_written = false; alarm_frame_written = false;
struct tm *stime = localtime(&start_time.tv_sec); struct tm *stime = localtime(&start_time.tv_sec);
std::string id_file;
path = stringtf("%s/%d", storage->Path(), monitor->Id()); path = stringtf("%s/%d", storage->Path(), monitor->Id());
// Try to make the Monitor Dir. Normally this would exist, but in odd cases might not. // Try to make the Monitor Dir. Normally this would exist, but in odd cases might not.
if ( mkdir(path.c_str(), 0755) ) { if ( mkdir(path.c_str(), 0755) ) {
if ( errno != EEXIST ) if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path, strerror(errno)); Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
} }
if ( storage->Scheme() == Storage::DEEP ) { if ( storage->Scheme() == Storage::DEEP ) {
@ -160,27 +146,26 @@ Event::Event(
dt_parts[4] = stime->tm_min; dt_parts[4] = stime->tm_min;
dt_parts[5] = stime->tm_sec; dt_parts[5] = stime->tm_sec;
char date_path[PATH_MAX] = ""; std::string date_path;
char time_path[PATH_MAX] = ""; std::string time_path;
char *time_path_ptr = time_path;
for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) { for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) {
path += stringtf("/%02d", dt_parts[i]); path += stringtf("/%02d", dt_parts[i]);
errno = 0;
if ( mkdir(path.c_str(), 0755) ) { if ( mkdir(path.c_str(), 0755) ) {
// FIXME This should not be fatal. Should probably move to a different storage area. // FIXME This should not be fatal. Should probably move to a different storage area.
if ( errno != EEXIST ) if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
} }
if ( i == 2 ) if ( i == 2 )
strncpy(date_path, path.c_str(), sizeof(date_path)); date_path = 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]);
} }
time_path = stringtf("%02d/%02d/%02d", stime->tm_hour, stime->tm_min, stime->tm_sec);
// Create event id symlink // Create event id symlink
std::string id_file = stringtf("%s/.%" PRIu64, date_path, id); id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id);
if ( symlink(time_path, id_file.c_str()) < 0 ) if ( symlink(time_path.c_str(), id_file.c_str()) < 0 )
Error("Can't symlink %s -> %s: %s", id_file.c_str(), path.c_str(), strerror(errno)); Error("Can't symlink %s -> %s: %s", id_file.c_str(), time_path.c_str(), strerror(errno));
} else if ( storage->Scheme() == Storage::MEDIUM ) { } else if ( storage->Scheme() == Storage::MEDIUM ) {
path += stringtf("/%04d-%02d-%02d", path += stringtf("/%04d-%02d-%02d",
stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday
@ -202,18 +187,19 @@ Event::Event(
} }
// Create empty id tag file // Create empty id tag file
std::string id_file = stringtf("%s/.%" PRIu64, path.c_str(), id); id_file = stringtf("%s/.%" PRIu64, path.c_str(), id);
if ( FILE *id_fp = fopen(id_file.c_str(), "w") ) if ( FILE *id_fp = fopen(id_file.c_str(), "w") ) {
fclose(id_fp); fclose(id_fp);
else } else {
Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno)); Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno));
}
} // deep storage or not } // deep storage or not
Debug(2, "Created event %d at %s", id, path.c_str()); Debug(2, "Created event %d at %s", id, path.c_str());
last_db_frame = 0; last_db_frame = 0;
video_name[0] = 0; video_name = "";
snapshot_file = path + "/snapshot.jpg"; snapshot_file = path + "/snapshot.jpg";
alarm_file = path + "/alarm.jpg"; alarm_file = path + "/alarm.jpg";
@ -221,7 +207,6 @@ Event::Event(
/* Save as video */ /* Save as video */
if ( monitor->GetOptVideoWriter() != 0 ) { if ( monitor->GetOptVideoWriter() != 0 ) {
Debug(2,"Video writer was %d", monitor->GetOptVideoWriter());
std::string container = monitor->OutputContainer(); std::string container = monitor->OutputContainer();
if ( container == "auto" || container == "" ) { if ( container == "auto" || container == "" ) {
if ( monitor->OutputCodec() == AV_CODEC_ID_H264 ) { if ( monitor->OutputCodec() == AV_CODEC_ID_H264 ) {
@ -231,33 +216,37 @@ Event::Event(
} }
} }
snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s.%s", id, "video", container.c_str()); video_name = stringtf("%" PRIu64 "-%s.%s", id, "video", container.c_str());
snprintf(video_file, sizeof(video_file), staticConfig.video_file_format, path.c_str(), video_name); snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
Debug(1,"Writing video file to %s", video_file); if ( mysql_query(&dbconn, sql) ) {
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
db_mutex.unlock();
return;
}
video_file = path + "/" + video_name;
Debug(1,"Writing video file to %s", video_file.c_str());
Camera * camera = monitor->getCamera(); Camera * camera = monitor->getCamera();
videoStore = new VideoStore( videoStore = new VideoStore(
video_file, video_file.c_str(),
container.c_str(), container.c_str(),
camera->get_VideoStream(), camera->get_VideoStream(),
( monitor->RecordAudio() ? camera->get_AudioStream() : NULL ), ( monitor->RecordAudio() ? camera->get_AudioStream() : NULL ),
monitor ); monitor );
if ( ! videoStore->open() ) { if ( !videoStore->open() ) {
delete videoStore; delete videoStore;
videoStore = NULL; videoStore = NULL;
save_jpegs |= 1; // Turn on jpeg storage save_jpegs |= 1; // Turn on jpeg storage
} }
} }
} // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent ) } // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent )
Event::~Event() { Event::~Event() {
// We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet. // We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet.
/* Close the video file */ /* Close the video file */
if ( videoStore ) { if ( videoStore ) {
Debug(2,"Deleting video store"); Debug(2, "Deleting video store");
delete videoStore; delete videoStore;
videoStore = NULL; videoStore = NULL;
} }
@ -279,13 +268,12 @@ Event::~Event() {
// update frame deltas to refer to video start time which may be a few frames before event start // update frame deltas to refer to video start time which may be a few frames before event start
struct timeval video_offset = {0}; struct timeval video_offset = {0};
struct timeval video_start_time = monitor->GetVideoWriterStartTime(); struct timeval video_start_time = monitor->GetVideoWriterStartTime();
if (video_start_time.tv_sec > 0) { if ( video_start_time.tv_sec > 0 ) {
timersub(&video_start_time, &start_time, &video_offset); timersub(&video_start_time, &start_time, &video_offset);
Debug(1, "Updating frames delta by %d sec %d usec", Debug(1, "Updating frames delta by %d sec %d usec",
video_offset.tv_sec, video_offset.tv_usec); video_offset.tv_sec, video_offset.tv_usec);
UpdateFramesDelta(video_offset.tv_sec + video_offset.tv_usec*1e-6); UpdateFramesDelta(video_offset.tv_sec + video_offset.tv_usec*1e-6);
} } else {
else {
Debug(3, "Video start_time %d sec %d usec not valid -- frame deltas not updated", Debug(3, "Video start_time %d sec %d usec not valid -- frame deltas not updated",
video_start_time.tv_sec, video_start_time.tv_usec); video_start_time.tv_sec, video_start_time.tv_usec);
} }
@ -293,12 +281,12 @@ Event::~Event() {
// Should not be static because we might be multi-threaded // Should not be static because we might be multi-threaded
char sql[ZM_SQL_LGE_BUFSIZ]; char sql[ZM_SQL_LGE_BUFSIZ];
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64, "UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
monitor->EventPrefix(), id, end_time.tv_sec, monitor->EventPrefix(), id, end_time.tv_sec,
delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec,
frames, alarm_frames, frames, alarm_frames,
tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score,
video_name, id ); id);
db_mutex.lock(); db_mutex.lock();
while ( mysql_query(&dbconn, sql) && !zm_terminate ) { while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
db_mutex.unlock(); db_mutex.unlock();
@ -307,7 +295,6 @@ Event::~Event() {
db_mutex.lock(); db_mutex.lock();
} }
db_mutex.unlock(); db_mutex.unlock();
} // Event::~Event() } // Event::~Event()
void Event::createNotes(std::string &notes) { void Event::createNotes(std::string &notes) {
@ -336,7 +323,7 @@ bool Event::WriteFrameImage(
int thisquality = int thisquality =
(alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality)) ? (alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality)) ?
config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default config.jpeg_alarm_file_quality : 0; // quality to use, zero is default
bool rc; bool rc;
@ -493,10 +480,9 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
frames++; frames++;
if ( save_jpegs & 1 ) { if ( save_jpegs & 1 ) {
static char event_file[PATH_MAX]; std::string event_file = stringtf(staticConfig.capture_file_format, path.c_str(), frames);
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path.c_str(), frames);
Debug(1, "Writing pre-capture frame %d", frames); Debug(1, "Writing pre-capture frame %d", frames);
WriteFrameImage(images[i], *(timestamps[i]), event_file); WriteFrameImage(images[i], *(timestamps[i]), event_file.c_str());
} }
//If this is the first frame, we should add a thumbnail to the event directory //If this is the first frame, we should add a thumbnail to the event directory
// ICON: We are working through the pre-event frames so this snapshot won't // ICON: We are working through the pre-event frames so this snapshot won't
@ -588,14 +574,14 @@ void Event::WriteDbFrames() {
void Event::UpdateFramesDelta(double offset) { void Event::UpdateFramesDelta(double offset) {
char sql[ZM_SQL_MED_BUFSIZ]; char sql[ZM_SQL_MED_BUFSIZ];
if (offset == 0.0) return; if ( offset == 0.0 ) return;
// the table is set to auto update timestamp so we force it to keep current value // the table is set to auto update timestamp so we force it to keep current value
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"UPDATE Frames SET timestamp = timestamp, Delta = Delta - (%.4f) WHERE EventId = %" PRIu64, "UPDATE Frames SET timestamp = timestamp, Delta = Delta - (%.4f) WHERE EventId = %" PRIu64,
offset, id); offset, id);
db_mutex.lock(); db_mutex.lock();
if (mysql_query(&dbconn, sql)) { if ( mysql_query(&dbconn, sql) ) {
db_mutex.unlock(); db_mutex.unlock();
Error("Can't update frames: %s, sql was %s", mysql_error(&dbconn), sql); Error("Can't update frames: %s, sql was %s", mysql_error(&dbconn), sql);
return; return;
@ -604,7 +590,6 @@ void Event::UpdateFramesDelta(double offset) {
Info("Updating frames delta by %0.2f sec to match video file", offset); Info("Updating frames delta by %0.2f sec to match video file", offset);
} }
void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) { void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) {
if ( !timestamp.tv_sec ) { if ( !timestamp.tv_sec ) {
Debug(1, "Not adding new frame, zero timestamp"); Debug(1, "Not adding new frame, zero timestamp");
@ -616,10 +601,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
bool write_to_db = false; bool write_to_db = false;
if ( save_jpegs & 1 ) { if ( save_jpegs & 1 ) {
static char event_file[PATH_MAX]; std::string event_file = stringtf(staticConfig.capture_file_format, path.c_str(), frames);
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); Debug(1, "Writing capture frame %d to %s", frames, event_file.c_str());
Debug(1, "Writing capture frame %d to %s", frames, event_file); if ( !WriteFrameImage(image, timestamp, event_file.c_str()) ) {
if ( !WriteFrameImage(image, timestamp, event_file) ) {
Error("Failed to write frame image"); Error("Failed to write frame image");
} }
} // end if save_jpegs } // end if save_jpegs
@ -651,10 +635,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
if ( alarm_image ) { if ( alarm_image ) {
if ( save_jpegs & 2 ) { if ( save_jpegs & 2 ) {
static char event_file[PATH_MAX]; std::string event_file = stringtf(staticConfig.analyse_file_format, path.c_str(), frames);
snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path.c_str(), frames);
Debug(1, "Writing analysis frame %d", frames); Debug(1, "Writing analysis frame %d", frames);
if ( ! WriteFrameImage(alarm_image, timestamp, event_file, true) ) { if ( ! WriteFrameImage(alarm_image, timestamp, event_file.c_str(), true) ) {
Error("Failed to write analysis frame image"); Error("Failed to write analysis frame image");
} }
} }
@ -670,10 +653,12 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
// The idea is to write out 1/sec // The idea is to write out 1/sec
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
if ( write_to_db || (frame_data.size() > (int)monitor->get_capture_fps()) ) { if ( write_to_db || (frame_data.size() > (unsigned int)monitor->get_capture_fps()) ) {
Debug(1, "Adding %d frames to DB", frame_data.size()); Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > fps %d",
frame_data.size(), write_to_db, (unsigned int)monitor->get_capture_fps());
WriteDbFrames(); WriteDbFrames();
last_db_frame = frames; last_db_frame = frames;
Debug(1, "Adding %d frames to DB, done", frame_data.size());
} }
// We are writing a Bulk frame // We are writing a Bulk frame

View File

@ -96,8 +96,8 @@ class Event {
VideoStore *videoStore; VideoStore *videoStore;
VideoWriter* videowriter; VideoWriter* videowriter;
char video_name[PATH_MAX]; std::string video_name;
char video_file[PATH_MAX]; std::string video_file;
int last_db_frame; int last_db_frame;
bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe. bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe.
Storage::Schemes scheme; Storage::Schemes scheme;
@ -140,15 +140,15 @@ class Event {
public: public:
static const char *getSubPath( struct tm *time ) { static const char *getSubPath( struct tm *time ) {
static char subpath[PATH_MAX] = ""; 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 ); 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 ); return subpath;
} }
static const char *getSubPath( time_t *time ) { static const char *getSubPath( time_t *time ) {
return Event::getSubPath( localtime( time ) ); return Event::getSubPath( localtime( time ) );
} }
char* getEventFile(void) { const char* getEventFile(void) {
return video_file; return video_file.c_str();
} }
public: public:
@ -156,27 +156,36 @@ class Event {
return pre_alarm_count; return pre_alarm_count;
} }
static void EmptyPreAlarmFrames() { static void EmptyPreAlarmFrames() {
if ( pre_alarm_count > 0 ) { while ( pre_alarm_count > 0 ) {
for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ ) { int i = pre_alarm_count - 1;
Debug(1, "EmptyreAlarmFrame: %d", i);
delete pre_alarm_data[i].image; delete pre_alarm_data[i].image;
pre_alarm_data[i].image = NULL;
if ( pre_alarm_data[i].alarm_frame ) {
delete pre_alarm_data[i].alarm_frame; delete pre_alarm_data[i].alarm_frame;
pre_alarm_data[i].alarm_frame = NULL;
} }
memset( pre_alarm_data, 0, sizeof(pre_alarm_data) ); pre_alarm_count--;
} }
pre_alarm_count = 0; pre_alarm_count = 0;
} }
static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ) { 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].image = new Image(*image);
pre_alarm_data[pre_alarm_count].timestamp = timestamp; pre_alarm_data[pre_alarm_count].timestamp = timestamp;
pre_alarm_data[pre_alarm_count].score = score; pre_alarm_data[pre_alarm_count].score = score;
if ( alarm_frame ) { if ( alarm_frame ) {
pre_alarm_data[pre_alarm_count].alarm_frame = new Image( *alarm_frame ); pre_alarm_data[pre_alarm_count].alarm_frame = new Image(*alarm_frame);
} }
pre_alarm_count++; pre_alarm_count++;
} }
void SavePreAlarmFrames() { void SavePreAlarmFrames() {
Debug(1, "SavePreAlarmFrame: %d", pre_alarm_count);
for ( int i = 0; i < pre_alarm_count; i++ ) { 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 ); AddFrame(
pre_alarm_data[i].image,
pre_alarm_data[i].timestamp,
pre_alarm_data[i].score,
pre_alarm_data[i].alarm_frame);
} }
EmptyPreAlarmFrames(); EmptyPreAlarmFrames();
} }

View File

@ -270,28 +270,20 @@ Image::~Image() {
/* Should be called as part of program shutdown to free everything */ /* Should be called as part of program shutdown to free everything */
void Image::Deinitialise() { void Image::Deinitialise() {
if ( !initialised ) return; if ( !initialised ) return;
/*
delete[] y_table;
delete[] uv_table;
delete[] r_v_table;
delete[] g_v_table;
delete[] g_u_table;
delete[] b_u_table;
*/
initialised = false; initialised = false;
if ( readjpg_dcinfo ) { if ( readjpg_dcinfo ) {
jpeg_destroy_decompress( readjpg_dcinfo ); jpeg_destroy_decompress(readjpg_dcinfo);
delete readjpg_dcinfo; delete readjpg_dcinfo;
readjpg_dcinfo = 0; readjpg_dcinfo = NULL;
} }
if ( decodejpg_dcinfo ) { if ( decodejpg_dcinfo ) {
jpeg_destroy_decompress( decodejpg_dcinfo ); jpeg_destroy_decompress(decodejpg_dcinfo);
delete decodejpg_dcinfo; delete decodejpg_dcinfo;
decodejpg_dcinfo = 0; decodejpg_dcinfo = NULL;
} }
for ( unsigned int quality=0; quality <= 100; quality += 1 ) { for ( unsigned int quality=0; quality <= 100; quality += 1 ) {
if ( writejpg_ccinfo[quality] ) { if ( writejpg_ccinfo[quality] ) {
jpeg_destroy_compress( writejpg_ccinfo[quality] ); jpeg_destroy_compress(writejpg_ccinfo[quality]);
delete writejpg_ccinfo[quality]; delete writejpg_ccinfo[quality];
writejpg_ccinfo[quality] = NULL; writejpg_ccinfo[quality] = NULL;
} }
@ -993,14 +985,12 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
struct jpeg_compress_struct *cinfo = writejpg_ccinfo[quality]; struct jpeg_compress_struct *cinfo = writejpg_ccinfo[quality];
FILE *outfile = NULL; FILE *outfile = NULL;
static int raw_fd = 0; static int raw_fd = 0;
bool need_create_comp = false;
raw_fd = 0; raw_fd = 0;
if ( !cinfo ) { if ( !cinfo ) {
cinfo = writejpg_ccinfo[quality] = new jpeg_compress_struct; cinfo = writejpg_ccinfo[quality] = new jpeg_compress_struct;
cinfo->err = jpeg_std_error(&jpg_err.pub); cinfo->err = jpeg_std_error(&jpg_err.pub);
jpeg_create_compress(cinfo); jpeg_create_compress(cinfo);
need_create_comp = true;
} }
if ( !on_blocking_abort ) { if ( !on_blocking_abort ) {
jpg_err.pub.error_exit = zm_jpeg_error_exit; jpg_err.pub.error_exit = zm_jpeg_error_exit;
@ -1018,8 +1008,6 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
return false; return false;
} }
} }
if ( need_create_comp )
jpeg_create_compress(cinfo);
if ( !on_blocking_abort ) { if ( !on_blocking_abort ) {
if ( (outfile = fopen(filename, "wb")) == NULL ) { if ( (outfile = fopen(filename, "wb")) == NULL ) {
@ -2842,7 +2830,6 @@ void Image::Deinterlace_Discard() {
} else { } else {
Error("Deinterlace called with unexpected colours: %d", colours); Error("Deinterlace called with unexpected colours: %d", colours);
} }
} }
void Image::Deinterlace_Linear() { void Image::Deinterlace_Linear() {

View File

@ -272,7 +272,7 @@ public:
//Image *Delta( const Image &image ) const; //Image *Delta( const Image &image ) const;
void Delta( const Image &image, Image* targetimage) const; void Delta( const Image &image, Image* targetimage) const;
const Coord centreCoord( const char *text ) const; const Coord centreCoord(const char *p_text) const;
void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 ); void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 );
void Annotate( const char *p_text, const Coord &coord, const unsigned int size=1, const Rgb fg_colour=RGB_WHITE, const Rgb bg_colour=RGB_BLACK ); void Annotate( const char *p_text, const Coord &coord, const unsigned int size=1, const Rgb fg_colour=RGB_WHITE, const Rgb bg_colour=RGB_BLACK );
Image *HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits=0 ); Image *HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits=0 );

View File

@ -779,7 +779,7 @@ void LocalCamera::Initialise() {
} }
} else { } else {
if ( vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0 ) { if ( vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0 ) {
Fatal("Failed to set video format: %s", strerror(errno)); Error("Failed to set video format: %s", strerror(errno));
} }
} }

View File

@ -350,7 +350,7 @@ Monitor::Monitor()
else else
event_close_mode = CLOSE_IDLE; event_close_mode = CLOSE_IDLE;
start_time = last_fps_time = time( 0 ); start_time = last_fps_time = time(0);
event = 0; event = 0;
last_section_mod = 0; last_section_mod = 0;
@ -416,7 +416,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++;
alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++;
if (analysis_fps > 0.0) { if ( analysis_fps > 0.0 ) {
uint64_t usec = round(1000000*pre_event_count/analysis_fps); uint64_t usec = round(1000000*pre_event_count/analysis_fps);
video_buffer_duration.tv_sec = usec/1000000; video_buffer_duration.tv_sec = usec/1000000;
video_buffer_duration.tv_usec = usec % 1000000; video_buffer_duration.tv_usec = usec % 1000000;
@ -590,16 +590,15 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
// maybe unneeded // maybe unneeded
// Should maybe store this for later use // Should maybe store this for later use
char monitor_dir[PATH_MAX]; std::string monitor_dir = stringtf("%s/%d", storage->Path(), id);
snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id);
if ( purpose == CAPTURE ) { if ( purpose == CAPTURE ) {
if ( mkdir(monitor_dir, 0755) && ( errno != EEXIST ) ) { if ( mkdir(monitor_dir.c_str(), 0755) && ( errno != EEXIST ) ) {
Error("Can't mkdir %s: %s", monitor_dir, strerror(errno)); Error("Can't mkdir %s: %s", monitor_dir.c_str(), strerror(errno));
} }
} else if ( purpose == ANALYSIS ) { } else if ( purpose == ANALYSIS ) {
if ( config.record_diag_images ) { if ( config.record_diag_images ) {
diag_path_r = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); diag_path_r = monitor_dir + "/diag-r.jpg";
diag_path_d = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); diag_path_d = monitor_dir + "/diag-d.jpg";
} }
} }
@ -1106,7 +1105,7 @@ Monitor::State Monitor::GetState() const {
return (State)shared_data->state; return (State)shared_data->state;
} }
int Monitor::GetImage( int index, int scale ) { int Monitor::GetImage(int index, int scale) {
if ( index < 0 || index > image_buffer_count ) { if ( index < 0 || index > image_buffer_count ) {
index = shared_data->last_write_index; index = shared_data->last_write_index;
} }
@ -1875,13 +1874,14 @@ bool Monitor::Analyse() {
&& (!event->AlarmFrames()) && (!event->AlarmFrames())
&& (event_close_mode == CLOSE_ALARM) && (event_close_mode == CLOSE_ALARM)
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= min_section_length ) && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= min_section_length )
&& ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) )
) { ) {
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins", Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
name, image_count, event->Id()); name, image_count, event->Id());
closeEvent(); closeEvent();
} else if ( event ) { } else if ( event ) {
// This is so if we need more than 1 alarm frame before going into alarm, so it is basically if we have enough alarm frames // This is so if we need more than 1 alarm frame before going into alarm, so it is basically if we have enough alarm frames
Debug(3, "pre-alarm-count in event %d, event frames %d, alarm frames %d event length %d >=? %d", Debug(3, "pre-alarm-count in event %d, event frames %d, alarm frames %d event length %d >=? %d min",
Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(), Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(),
( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length ( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length
); );
@ -1911,9 +1911,9 @@ bool Monitor::Analyse() {
shared_data->state = state = ALARM; shared_data->state = state = ALARM;
Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name, image_count, event->Id()); Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name, image_count, event->Id());
} }
if ( alarm_frame_count ) { if ( alarm_frame_count ) {
Debug(1, "alarm frame count so SavePreAlarmFrames");
event->SavePreAlarmFrames(); event->SavePreAlarmFrames();
} }
} else if ( state != PREALARM ) { } else if ( state != PREALARM ) {
@ -2305,7 +2305,7 @@ int Monitor::Capture() {
captureResult = camera->Capture(*packet); captureResult = camera->Capture(*packet);
gettimeofday(packet->timestamp, NULL); gettimeofday(packet->timestamp, NULL);
if ( captureResult < 0 ) { if ( captureResult < 0 ) {
Debug(2,"failed capture"); Debug(2, "failed capture");
// Unable to capture image for temporary reason // Unable to capture image for temporary reason
// Fake a signal loss image // Fake a signal loss image
Rgb signalcolor; Rgb signalcolor;
@ -2392,6 +2392,7 @@ int Monitor::Capture() {
} }
if ( orientation != ROTATE_0 ) { if ( orientation != ROTATE_0 ) {
Debug(2, "Doing rotation");
switch ( orientation ) { switch ( orientation ) {
case ROTATE_0 : case ROTATE_0 :
// No action required // No action required
@ -2412,13 +2413,16 @@ int Monitor::Capture() {
capture_image->MaskPrivacy(privacy_bitmask); capture_image->MaskPrivacy(privacy_bitmask);
if ( config.timestamp_on_capture ) { if ( config.timestamp_on_capture ) {
Debug(1, "Timestamping");
TimestampImage(capture_image, packet->timestamp); TimestampImage(capture_image, packet->timestamp);
} }
shared_data->signal = signal_check_points ? CheckSignal(capture_image) : true; shared_data->signal = signal_check_points ? CheckSignal(capture_image) : true;
Debug(1, "signal check points? %d", signal_check_points);
shared_data->last_write_index = index; shared_data->last_write_index = index;
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
image_count++; image_count++;
Debug(2, "Unlocking packet");
packet->unlock(); packet->unlock();
if ( fps_report_interval && ( !(image_count%fps_report_interval) || image_count == 5 ) ) { if ( fps_report_interval && ( !(image_count%fps_report_interval) || image_count == 5 ) ) {
@ -2478,13 +2482,13 @@ int Monitor::Capture() {
return captureResult; return captureResult;
} // end Monitor::Capture } // end Monitor::Capture
void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const { void Monitor::TimestampImage(Image *ts_image, const struct timeval *ts_time) const {
if ( !label_format[0] ) if ( !label_format[0] )
return; return;
// Expand the strftime macros first // Expand the strftime macros first
char label_time_text[256]; char label_time_text[256];
strftime( label_time_text, sizeof(label_time_text), label_format, localtime( &ts_time->tv_sec ) ); strftime(label_time_text, sizeof(label_time_text), label_format, localtime(&ts_time->tv_sec));
char label_text[1024]; char label_text[1024];
const char *s_ptr = label_time_text; const char *s_ptr = label_time_text;
@ -2494,15 +2498,15 @@ void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) c
bool found_macro = false; bool found_macro = false;
switch ( *(s_ptr+1) ) { switch ( *(s_ptr+1) ) {
case 'N' : case 'N' :
d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name ); d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name);
found_macro = true; found_macro = true;
break; break;
case 'Q' : case 'Q' :
d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext ); d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext);
found_macro = true; found_macro = true;
break; break;
case 'f' : case 'f' :
d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000 ); d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000);
found_macro = true; found_macro = true;
break; break;
} }
@ -2514,7 +2518,9 @@ void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) c
*d_ptr++ = *s_ptr++; *d_ptr++ = *s_ptr++;
} // end while } // end while
*d_ptr = '\0'; *d_ptr = '\0';
Debug(2, "annotating %s", label_text);
ts_image->Annotate(label_text, label_coord, label_size); ts_image->Annotate(label_text, label_coord, label_size);
Debug(2, "done annotating %s", label_text);
} // end void Monitor::TimestampImage } // end void Monitor::TimestampImage
bool Monitor::closeEvent() { bool Monitor::closeEvent() {

View File

@ -78,7 +78,9 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
// We signal on every packet because someday we may analyze sound // We signal on every packet because someday we may analyze sound
Debug(2,"Signalling"); Debug(2,"Signalling");
condition->signal(); condition->signal();
Debug(2," after Signalling");
mutex.unlock(); mutex.unlock();
Debug(2," after unlock");
return true; return true;
} // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) } // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet)

View File

@ -48,18 +48,18 @@ while (my $line = <F>) {
$in_head-- if $line =~ /^$/ and $in_head; $in_head-- if $line =~ /^$/ and $in_head;
next while $in_head; next while $in_head;
unless ($line =~ /^\s+(0x..), \/\* (........)/) { unless ($line =~ /^\s+(0x..), \/\* (........)/) {
$line =~ s/static unsigned char fontdata/static unsigned int bigfontdata/; #$line =~ s/static unsigned char fontdata/static unsigned int bigfontdata/;
print $line; print $line;
next; next;
} }
my $code = $1; my $code = $1;
my $bincode = $2; my $bincode = $2;
$bincode = "$1$1$2$2$3$3$4$4$5$5$6$6$7$7$8$8" if $bincode =~ /(.)(.)(.)(.)(.)(.)(.)(.)$/; $bincode = "$1$1$2$2$3$3$4$4$5$5$6$6$7$7$8$8" if $bincode =~ /(.)(.)(.)(.)(.)(.)(.)(.)$/;
$bincode =~ s/ /1/g; #$bincode =~ s/ /1/g;
my $intcode = unpack("N", pack("B32", substr("0" x 32 . $bincode, -32))); #my $intcode = unpack("N", pack("B32", substr("0" x 32 . $bincode, -32)));
my $hexcode = sprintf("%#x", $intcode); #my $hexcode = sprintf("%#x", $intcode);
$hexcode =~ s/^0$/0x0/; #$hexcode =~ s/^0$/0x0/;
$bincode =~ s/1/ /g; #$bincode =~ s/1/ /g;
print sprintf("\t%10s, /* %s */\n", $hexcode, $bincode); print sprintf("\t%10s, /* %s */\n", $hexcode, $bincode);
print sprintf("\t%10s, /* %s */\n", $hexcode, $bincode); print sprintf("\t%10s, /* %s */\n", $hexcode, $bincode);
} }

View File

@ -842,9 +842,15 @@ function daemonStatus($daemon, $args=false) {
initDaemonStatus(); initDaemonStatus();
$string = $daemon; $string = $daemon;
if ( $args ) if ( $args ) {
if ( is_array($args) ) {
$string .= join(' ', $args);
ZM\Warning("daemonStatus args: $string");
} else {
$string .= ' ' . $args; $string .= ' ' . $args;
return( strpos($daemon_status, "'$string' running") !== false ); }
}
return ( strpos($daemon_status, "'$string' running") !== false );
} }
function zmcStatus($monitor) { function zmcStatus($monitor) {