Merge branch 'master' of github.com:ZoneMinder/zoneminder

pull/2993/head
Isaac Connor 2020-07-22 17:37:52 -04:00
commit 1416bc547e
8 changed files with 276 additions and 235 deletions

View File

@ -20,18 +20,16 @@ sub START {
sub Subscribe {
my ($self, $body, $header) = @_;
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({
operation => 'Subscribe',
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/Subscribe',
style => 'document',
body => {
'use' => 'literal',
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
encodingStyle => '',
parts => [qw( WSNotification::Elements::Subscribe )],
use => 'literal',
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
encodingStyle => '',
parts => [qw( WSNotification::Elements::Subscribe )],
},
header => {
@ -42,39 +40,30 @@ sub Subscribe {
}, $body, $header);
}
sub GetCurrentMessage {
my ($self, $body, $header) = @_;
die "GetCurrentMessage must be called as object method (\$self is <$self>)" if not blessed($self);
return $self->SUPER::call({
operation => 'GetCurrentMessage',
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/GetCurrentMessage',
style => 'document',
body => {
my ($self, $body, $header) = @_;
die "GetCurrentMessage must be called as object method (\$self is <$self>)" if not blessed($self);
return $self->SUPER::call({
operation => 'GetCurrentMessage',
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/GetCurrentMessage',
style => 'document',
body => {
use => 'literal',
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
encodingStyle => '',
parts => [qw( WSNotification::Elements::GetCurrentMessage )],
'use' => 'literal',
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
encodingStyle => '',
parts => [qw( WSNotification::Elements::GetCurrentMessage )],
},
header => {
},
header => {
},
headerfault => {
}
}, $body, $header);
},
headerfault => {
}
}, $body, $header);
}
1;
__END__
=pod

View File

@ -87,7 +87,7 @@ Event::Event(
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, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) VALUES ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d, '%s' )",
snprintf(sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) VALUES ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '%s', %d, '%s' )",
monitor->Id(),
storage->Id(),
start_time.tv_sec,
@ -98,6 +98,7 @@ Event::Event(
state_id,
monitor->getOrientation(),
videoEvent,
( monitor->GetOptVideoWriter() != 0 ? "video.mp4" : "" ),
monitor->GetOptSaveJPEGs(),
storage->SchemeString().c_str()
);
@ -108,23 +109,7 @@ Event::Event(
return;
}
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();
if ( untimedEvent ) {
Warning("Event %d has zero time, setting to current", id);
@ -136,14 +121,13 @@ Event::Event(
max_score = 0;
alarm_frame_written = false;
char id_file[PATH_MAX];
std::string id_file;
char *path_ptr = path;
path_ptr += snprintf(path_ptr, sizeof(path), "%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.
if ( mkdir(path, 0755) ) {
if ( mkdir(path.c_str(), 0755) ) {
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 ) {
@ -156,97 +140,103 @@ Event::Event(
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]);
std::string date_path;
std::string time_path;
errno = 0;
if ( mkdir(path, 0755) ) {
for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) {
path += stringtf("/%02d", dt_parts[i]);
if ( mkdir(path.c_str(), 0755) ) {
// FIXME This should not be fatal. Should probably move to a different storage area.
if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path, strerror(errno));
Error("Can't mkdir %s: %s", path.c_str(), 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]);
date_path = path;
}
time_path = stringtf("%02d/%02d/%02d", stime->tm_hour, stime->tm_min, stime->tm_sec);
// Create event id symlink
snprintf(id_file, sizeof(id_file), "%s/.%" PRIu64, date_path, id);
if ( symlink(time_path, id_file) < 0 )
Error("Can't symlink %s -> %s: %s", id_file, path, strerror(errno));
id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id);
if ( symlink(time_path.c_str(), id_file.c_str()) < 0 )
Error("Can't symlink %s -> %s: %s", id_file.c_str(), time_path.c_str(), strerror(errno));
} else if ( storage->Scheme() == Storage::MEDIUM ) {
path_ptr += snprintf(
path_ptr, sizeof(path), "/%04d-%02d-%02d",
path += stringtf("/%04d-%02d-%02d",
stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday
);
if ( mkdir(path, 0755) ) {
if ( mkdir(path.c_str(), 0755) ) {
if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path, strerror(errno));
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
}
path_ptr += snprintf(path_ptr, sizeof(path), "/%" PRIu64, id);
if ( mkdir(path, 0755) ) {
path += stringtf("/%" PRIu64, id);
if ( mkdir(path.c_str(), 0755) ) {
if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path, strerror(errno));
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
}
} else {
path_ptr += snprintf(path_ptr, sizeof(path), "/%" PRIu64, id);
if ( mkdir(path, 0755) ) {
path += stringtf("/%" PRIu64, id);
if ( mkdir(path.c_str(), 0755) ) {
if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path, strerror(errno));
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
}
// Create empty id tag file
snprintf(id_file, sizeof(id_file), "%s/.%" PRIu64, path, id);
if ( FILE *id_fp = fopen(id_file, "w") )
id_file = stringtf("%s/.%" PRIu64, path.c_str(), id);
if ( FILE *id_fp = fopen(id_file.c_str(), "w") ) {
fclose(id_fp);
else
Error("Can't fopen %s: %s", id_file, strerror(errno));
} else {
Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno));
}
} // deep storage or not
last_db_frame = 0;
video_name[0] = 0;
video_name = "";
snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path);
snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path);
snapshot_file = path + "/snapshot.jpg";
alarm_file = path + "/alarm.jpg";
/* Save as video */
if ( monitor->GetOptVideoWriter() != 0 ) {
snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s", id, "video.mp4");
snprintf(video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name);
Debug(1,"Writing video file to %s", video_file );
video_name = stringtf("%" PRIu64 "-%s", id, "video.mp4");
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
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());
/* X264 MP4 video writer */
if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) {
#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.c_str(),
monitor->Width(), monitor->Height(),
monitor->Colours(), monitor->SubpixelOrder(),
monitor->GetOptEncoderParams());
#else
Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)");
#endif
}
if ( videowriter != NULL ) {
/* Open the video stream */
int nRet = videowriter->Open();
if ( nRet != 0 ) {
Error("Failed opening video stream");
delete videowriter;
videowriter = NULL;
}
}
if ( videowriter != NULL ) {
/* Open the video stream */
int nRet = videowriter->Open();
if ( nRet != 0 ) {
Error("Failed opening video stream");
delete videowriter;
videowriter = NULL;
}
}
}
} else {
/* No video object */
videowriter = NULL;
}
} // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent )
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.
/* Close the video file */
@ -276,13 +266,12 @@ Event::~Event() {
// 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_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);
Debug(1, "Updating frames delta by %d sec %d usec",
video_offset.tv_sec, video_offset.tv_usec);
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",
video_start_time.tv_sec, video_start_time.tv_usec);
}
@ -290,12 +279,12 @@ Event::~Event() {
// Should not be static because we might be multi-threaded
char sql[ZM_SQL_LGE_BUFSIZ];
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,
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 );
id);
db_mutex.lock();
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
db_mutex.unlock();
@ -304,7 +293,6 @@ Event::~Event() {
db_mutex.lock();
}
db_mutex.unlock();
} // Event::~Event()
void Event::createNotes(std::string &notes) {
@ -329,7 +317,7 @@ bool Event::WriteFrameImage(
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
config.jpeg_alarm_file_quality : 0; // quality to use, zero is default
bool rc;
@ -507,17 +495,16 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
frames++;
if ( monitor->GetOptSaveJPEGs() & 1 ) {
static char event_file[PATH_MAX];
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
std::string event_file = stringtf(staticConfig.capture_file_format, path, 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
// ICON: We are working through the pre-event frames so this snapshot won't
// neccessarily be of the motion. But some events are less than 10 frames,
// so I am changing this to 1, but we should overwrite it later with a better snapshot.
if ( frames == 1 ) {
WriteFrameImage(images[i], *(timestamps[i]), snapshot_file);
WriteFrameImage(images[i], *(timestamps[i]), snapshot_file.c_str());
}
if ( videowriter != NULL ) {
@ -589,14 +576,14 @@ void Event::WriteDbFrames() {
void Event::UpdateFramesDelta(double offset) {
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
snprintf(sql, sizeof(sql),
"UPDATE Frames SET timestamp = timestamp, Delta = Delta - (%.4f) WHERE EventId = %" PRIu64,
offset, id);
db_mutex.lock();
if (mysql_query(&dbconn, sql)) {
if ( mysql_query(&dbconn, sql) ) {
db_mutex.unlock();
Error("Can't update frames: %s, sql was %s", mysql_error(&dbconn), sql);
return;
@ -605,7 +592,6 @@ void Event::UpdateFramesDelta(double 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) {
if ( !timestamp.tv_sec ) {
Debug(1, "Not adding new frame, zero timestamp");
@ -620,10 +606,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
score = 0;
if ( monitor->GetOptSaveJPEGs() & 1 ) {
static char event_file[PATH_MAX];
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
Debug(1, "Writing capture frame %d to %s", frames, event_file);
if ( !WriteFrameImage(image, timestamp, event_file) ) {
std::string event_file = stringtf(staticConfig.capture_file_format, path, frames);
Debug(1, "Writing capture frame %d to %s", frames, event_file.c_str());
if ( !WriteFrameImage(image, timestamp, event_file.c_str()) ) {
Error("Failed to write frame image");
}
}
@ -631,7 +616,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
// If this is the first frame, we should add a thumbnail to the event directory
if ( (frames == 1) || (score > (int)max_score) ) {
write_to_db = true; // web ui might show this as thumbnail, so db needs to know about it.
WriteFrameImage(image, timestamp, snapshot_file);
WriteFrameImage(image, timestamp, snapshot_file.c_str());
}
// We are writing an Alarm frame
@ -640,7 +625,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
if ( !alarm_frame_written ) {
write_to_db = true; // OD processing will need it, so the db needs to know about it
alarm_frame_written = true;
WriteFrameImage(image, timestamp, alarm_file);
WriteFrameImage(image, timestamp, alarm_file.c_str());
}
alarm_frames++;
@ -650,10 +635,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
if ( alarm_image ) {
if ( monitor->GetOptSaveJPEGs() & 2 ) {
static char event_file[PATH_MAX];
snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames);
std::string event_file = stringtf(staticConfig.analyse_file_format, path, 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");
}
}
@ -673,10 +657,12 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
// The idea is to write out 1/sec
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
if ( write_to_db || (frame_data.size() > (int)monitor->get_fps()) ) {
Debug(1, "Adding %d frames to DB", frame_data.size());
if ( write_to_db || (frame_data.size() > (unsigned int)monitor->get_fps()) ) {
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_fps());
WriteDbFrames();
last_db_frame = frames;
Debug(1, "Adding %d frames to DB, done", frame_data.size());
}
// We are writing a Bulk frame

View File

@ -89,15 +89,17 @@ class Event {
bool alarm_frame_written;
unsigned int tot_score;
unsigned int max_score;
char path[PATH_MAX];
char snapshot_file[PATH_MAX];
char alarm_file[PATH_MAX];
std::string path;
std::string snapshot_file;
std::string alarm_file;
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];
std::string video_name;
std::string video_file;
std::string timecodes_name;
std::string timecodes_file;
int last_db_frame;
Storage::Schemes scheme;
@ -137,15 +139,15 @@ class Event {
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 );
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;
const char* getEventFile(void) {
return video_file.c_str();
}
public:
@ -153,28 +155,37 @@ class Event {
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) );
}
while ( pre_alarm_count > 0 ) {
int i = pre_alarm_count - 1;
Debug(1, "EmptyreAlarmFrame: %d", i);
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;
pre_alarm_data[i].alarm_frame = NULL;
}
pre_alarm_count--;
}
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 );
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_data[pre_alarm_count].alarm_frame = new Image(*alarm_frame);
}
pre_alarm_count++;
}
void SavePreAlarmFrames() {
Debug(1, "SavePreAlarmFrame: %d", pre_alarm_count);
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();
}
};

View File

@ -265,18 +265,18 @@ void Image::Deinitialise() {
if ( !initialised ) return;
initialised = false;
if ( readjpg_dcinfo ) {
jpeg_destroy_decompress( readjpg_dcinfo );
jpeg_destroy_decompress(readjpg_dcinfo);
delete readjpg_dcinfo;
readjpg_dcinfo = 0;
readjpg_dcinfo = NULL;
}
if ( decodejpg_dcinfo ) {
jpeg_destroy_decompress( decodejpg_dcinfo );
jpeg_destroy_decompress(decodejpg_dcinfo);
delete decodejpg_dcinfo;
decodejpg_dcinfo = 0;
decodejpg_dcinfo = NULL;
}
for ( unsigned int quality=0; quality <= 100; quality += 1 ) {
if ( writejpg_ccinfo[quality] ) {
jpeg_destroy_compress( writejpg_ccinfo[quality] );
jpeg_destroy_compress(writejpg_ccinfo[quality]);
delete writejpg_ccinfo[quality];
writejpg_ccinfo[quality] = NULL;
}
@ -1011,14 +1011,12 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
struct jpeg_compress_struct *cinfo = writejpg_ccinfo[quality];
FILE *outfile = NULL;
static int raw_fd = 0;
bool need_create_comp = false;
raw_fd = 0;
if ( !cinfo ) {
cinfo = writejpg_ccinfo[quality] = new jpeg_compress_struct;
cinfo->err = jpeg_std_error(&jpg_err.pub);
jpeg_create_compress(cinfo);
need_create_comp = true;
}
if ( !on_blocking_abort ) {
jpg_err.pub.error_exit = zm_jpeg_error_exit;
@ -1036,8 +1034,6 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
return false;
}
}
if ( need_create_comp )
jpeg_create_compress(cinfo);
if ( !on_blocking_abort ) {
if ( (outfile = fopen(filename, "wb")) == NULL ) {
@ -2860,7 +2856,6 @@ void Image::Deinterlace_Discard() {
} else {
Error("Deinterlace called with unexpected colours: %d", colours);
}
}
void Image::Deinterlace_Linear() {

View File

@ -727,9 +727,11 @@ Monitor::~Monitor() {
}
delete[] pre_event_buffer;
}
if ( Event::PreAlarmCount() )
Event::EmptyPreAlarmFrames();
} else if ( purpose == CAPTURE ) {
shared_data->valid = false;
memset( mem_ptr, 0, mem_size );
memset(mem_ptr, 0, mem_size);
}
#if ZM_MEM_MAPPED
@ -1535,22 +1537,23 @@ bool Monitor::Analyse() {
&& (!event->AlarmFrames())
&& (event_close_mode == CLOSE_ALARM)
&& ( ( 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",
name, image_count, event->Id());
closeEvent();
} 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
Debug(3, "pre-alarm-count in event %d, event frames %d, alarm frames %d event length %d >=? %d",
Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(),
( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length
);
}
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
// lets construct alarm cause. It will contain cause + names of zones alarmed
std::string alarm_cause = "";
for ( int i=0; i < n_zones; i++ ) {
if ( zones[i]->Alarmed() ) {
// 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 min",
Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(),
( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length
);
}
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
// lets construct alarm cause. It will contain cause + names of zones alarmed
std::string alarm_cause = "";
for ( int i=0; i < n_zones; i++ ) {
if ( zones[i]->Alarmed() ) {
alarm_cause = alarm_cause + "," + std::string(zones[i]->Label());
}
}
@ -1627,11 +1630,13 @@ bool Monitor::Analyse() {
}
}
event->AddFrames(pre_event_images, images, timestamps);
}
} // end if pre_event_images
if ( alarm_frame_count ) {
Debug(1, "alarm frame count so SavePreAlarmFrames");
event->SavePreAlarmFrames();
}
}
} // end if event
} else if ( state != PREALARM ) {
Info("%s: %03d - Gone into prealarm state", name, image_count);
shared_data->state = state = PREALARM;
@ -1670,10 +1675,11 @@ bool Monitor::Analyse() {
} else {
shared_data->state = state = TAPE;
}
}
if ( Event::PreAlarmCount() )
Event::EmptyPreAlarmFrames();
} // end if score or not
// Not in PREALARM state anymore, can clear PreAlarmCount
if ( Event::PreAlarmCount() )
Event::EmptyPreAlarmFrames();
}
} // end if score or not
if ( state != IDLE ) {
if ( state == PREALARM || state == ALARM ) {
@ -1691,10 +1697,11 @@ bool Monitor::Analyse() {
} // end if zone is alarmed
} // end foreach zone
if ( state == PREALARM )
if ( state == PREALARM ) {
Event::AddPreAlarmFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
else
event->AddFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
} else {
event->AddFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
}
} else {
// Not doing alarm frame storage
if ( state == PREALARM ) {

View File

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

View File

@ -256,21 +256,21 @@ function getNavBarHTML($reload = null) {
$status = $running ? ($state ? $state : translate('Running')) : translate('Stopped');
?>
<div class="navbar navbar-inverse navbar-static-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#main-header-nav" aria-expanded="false">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#main-header-nav" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</button>
<div class="navbar-brand">
<a href="<?php echo validHtmlStr(ZM_HOME_URL); ?>" target="<?php echo validHtmlStr(ZM_WEB_TITLE); ?>"><?php echo ZM_HOME_CONTENT ?></a>
</div>
</div>
</div>
<div class="collapse navbar-collapse" id="main-header-nav">
<ul class="nav navbar-nav">
<div class="collapse navbar-collapse" id="main-header-nav">
<ul class="nav navbar-nav">
<?php
if ( $user and $user['Username'] ) {
if ( canView('Monitors') ) {
@ -378,34 +378,52 @@ if ( $user and $user['Username'] ) {
if ( (!ZM_OPT_USE_AUTH) or $user ) {
if ($reload == 'reload') ob_start();
?>
<div id="reload" class="container-fluid reduced-text">
<div id="reload" class="container-fluid reduced-text">
<div id="Bandwidth" class="pull-left">
<?php echo makePopupLink( '?view=bandwidth', 'zmBandwidth', 'bandwidth', "<i class='material-icons md-18'>network_check</i>&nbsp;".$bandwidth_options[$_COOKIE['zmBandwidth']] . ' ', ($user && $user['MaxBandwidth'] != 'low' ) ) ?>
<?php echo getBandwidthHTML($bandwidth_options,$user) ?>
</div>
<div id="Version" class="pull-right">
<?php echo makePopupLink( '?view=version', 'zmVersion', 'version', '<span class="version '.$versionClass.'">v'.ZM_VERSION.'</span>', canEdit('System') ) ?>
<?php echo getZMVersionHTML($versionClass) ?>
</div>
<ul class="list-inline">
<li class="Load"><i class="material-icons md-18">trending_up</i>&nbsp;<?php echo translate('Load') ?>: <?php echo getLoad() ?></li>
<i class="material-icons md-18">storage</i>
<?php
<?php echo getSysLoadHTML() ?>
<?php echo getDbConHTML() ?>
<?php echo getStorageHTML() ?>
<?php echo getShmHTML() ?>
</ul>
<?php echo getConsoleBannerHTML() ?>
</div><!-- End .footer/reload -->
<?php
if ($reload == 'reload') return ob_get_clean();
} // end if (!ZM_OPT_USE_AUTH) or $user )
?>
</div>
</div><!-- End .navbar .navbar-default -->
<?php
return ob_get_clean();
} // end function getNavBarHTML()
function getSysLoadHTML() {
echo '<li class="Load">';
echo '<i class="material-icons md-18">trending_up</i>';
echo '&nbsp;'.translate('Load').':'.getLoad();
echo '</li>';
}
function getDbConHTML() {
$connections = dbFetchOne('SHOW status WHERE variable_name=\'threads_connected\'', 'Value');
$max_connections = dbFetchOne('SHOW variables WHERE variable_name=\'max_connections\'', 'Value');
$percent_used = $max_connections ? 100 * $connections / $max_connections : 100;
echo '<li'. ( $percent_used > 90 ? ' class="warning"' : '' ).'>'.translate('DB').':'.$connections.'/'.$max_connections.'</li>';
?>
<li><?php echo translate('Storage') ?>:
<?php
$storage_areas = ZM\Storage::find(array('Enabled'=>true));
$storage_paths = null;
$storage_areas_with_no_server_id = array();
foreach ( $storage_areas as $area ) {
$storage_paths[$area->Path()] = $area;
if ( ! $area->ServerId() ) {
$storage_areas_with_no_server_id[] = $area;
}
}
$func = function($S){
$class = $percent_used > 90 ? 'warning' : '';
echo '<i class="material-icons md-18">storage</i>';
echo '<li class="'. $class .'">'.translate('DB').':'.$connections.'/'.$max_connections.'</li>';
}
function getStorageHTML() {
$func = function($S) {
$class = '';
if ( $S->disk_usage_percent() > 98 ) {
$class = 'error';
@ -414,14 +432,31 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) {
}
$title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()).
( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' );
return '<span class="'.$class.'" title="'.$title.'">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>';
};
return '<span class="'.$class.'" title="'.$title.'">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>
'; };
#$func = function($S){ return '<span title="">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; };
if ( count($storage_areas) > 4 )
$storage_areas = ZM\Storage::find(array('Enabled'=>true));
$num_storage_areas = count($storage_areas);
$storage_paths = null;
$storage_areas_with_no_server_id = array();
foreach ( $storage_areas as $area ) {
$storage_paths[$area->Path()] = $area;
if ( ! $area->ServerId() ) {
$storage_areas_with_no_server_id[] = $area;
}
}
echo '<li>'.translate('Storage').':';
if ( $num_storage_areas > 4 ) {
$storage_areas = $storage_areas_with_no_server_id;
if ( count($storage_areas) <= 4 )
} else {
echo implode(', ', array_map($func, $storage_areas));
}
echo '</li>';
}
function getShmHTML() {
$shm_percent = getDiskPercent(ZM_PATH_MAP);
$shm_total_space = disk_total_space(ZM_PATH_MAP);
$shm_used = $shm_total_space - disk_free_space(ZM_PATH_MAP);
@ -433,21 +468,24 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) {
$class = 'warning';
}
echo ' <span class="'.$class.'" title="' . human_filesize($shm_used).' of '.human_filesize($shm_total_space).'">'.ZM_PATH_MAP.': '.$shm_percent.'%</span>';
?></li>
</ul>
<?php if ( defined('ZM_WEB_CONSOLE_BANNER') and ZM_WEB_CONSOLE_BANNER != '' ) { ?>
<h3 id="development"><?php echo validHtmlStr(ZM_WEB_CONSOLE_BANNER); ?></h3>
<?php } ?>
<!-- End .footer/reload --></div>
<?php
if ($reload == 'reload') return ob_get_clean();
} // end if (!ZM_OPT_USE_AUTH) or $user )
?>
</div>
</div><!-- End .navbar .navbar-default -->
<?php
return ob_get_clean();
} // end function getNavBarHTML()
}
function getConsoleBannerHTML() {
if ( defined('ZM_WEB_CONSOLE_BANNER') and ZM_WEB_CONSOLE_BANNER != '' ) {
echo '<h3 id="development">'.validHtmlStr(ZM_WEB_CONSOLE_BANNER).'</h3>';
}
}
function getBandwidthHTML($bandwidth_options,$user) {
echo makePopupLink( '?view=bandwidth', 'zmBandwidth', 'bandwidth', "<i class='material-icons md-18'>network_check</i>&nbsp;".$bandwidth_options[$_COOKIE['zmBandwidth']] . ' ', ($user && $user['MaxBandwidth'] != 'low' ));
}
function getZMVersionHTML($versionClass) {
echo makePopupLink( '?view=version', 'zmVersion', 'version', '<span class="version '.$versionClass.'">v'.ZM_VERSION.'</span>', canEdit('System') );
}
function xhtmlFooter() {
global $cspNonce;

View File

@ -807,9 +807,18 @@ switch ( $tab ) {
<?php
} else {
?>
<tr><td><?php echo translate('DeviceChannel') ?></td><td><select name="newMonitor[Channel]"><?php foreach ( $v4l2DeviceChannels as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Channel()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('DeviceFormat') ?></td><td><select name="newMonitor[Format]"><?php foreach ( $v4l2DeviceFormats as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Format()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('CapturePalette') ?></td><td><select name="newMonitor[Palette]"><?php foreach ( $v4l2LocalPalettes as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Palette()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr>
<td><?php echo translate('DeviceChannel') ?></td>
<td><?php echo htmlSelect('newMonitor[Channel]', $v4l2DeviceChannels, $monitor->Channel()); ?></td>
</tr>
<tr>
<td><?php echo translate('DeviceFormat') ?></td>
<td><?php echo htmlSelect('newMonitor[Format]', $v4l2DeviceFormats, $monitor->Format()); ?></td>
</tr>
<tr>
<td><?php echo translate('CapturePalette') ?></td>
<td><?php echo htmlSelect('newMonitor[Palette]', $v4l2LocalPalettes, $monitor->Palette()); ?></td>
</tr>
<?php
}
?>