Merge branch 'max_queue_size'

This commit is contained in:
Isaac Connor 2021-03-26 17:03:52 -04:00
commit 1d99bd5cb3
13 changed files with 143 additions and 78 deletions

View File

@ -497,11 +497,12 @@ CREATE TABLE `Monitors` (
`LabelX` smallint(5) unsigned NOT NULL default '0', `LabelX` smallint(5) unsigned NOT NULL default '0',
`LabelY` smallint(5) unsigned NOT NULL default '0', `LabelY` smallint(5) unsigned NOT NULL default '0',
`LabelSize` smallint(5) unsigned NOT NULL DEFAULT '1', `LabelSize` smallint(5) unsigned NOT NULL DEFAULT '1',
`ImageBufferCount` smallint(5) unsigned NOT NULL default '100', `ImageBufferCount` smallint(5) unsigned NOT NULL default '3',
`WarmupCount` smallint(5) unsigned NOT NULL default '25', `MaxImageBufferCount` smallint(5) unsigned NOT NULL default '0',
`WarmupCount` smallint(5) unsigned NOT NULL default '0',
`PreEventCount` smallint(5) unsigned NOT NULL default '10', `PreEventCount` smallint(5) unsigned NOT NULL default '10',
`PostEventCount` smallint(5) unsigned NOT NULL default '10', `PostEventCount` smallint(5) unsigned NOT NULL default '10',
`StreamReplayBuffer` int(10) unsigned NOT NULL default '1000', `StreamReplayBuffer` int(10) unsigned NOT NULL default '0',
`AlarmFrameCount` smallint(5) unsigned NOT NULL default '1', `AlarmFrameCount` smallint(5) unsigned NOT NULL default '1',
`SectionLength` int(10) unsigned NOT NULL default '600', `SectionLength` int(10) unsigned NOT NULL default '600',
`MinSectionLength` int(10) unsigned NOT NULL default '10', `MinSectionLength` int(10) unsigned NOT NULL default '10',

19
db/zm_update-1.35.22.sql Normal file
View File

@ -0,0 +1,19 @@
--
-- Add MaxImageBufferCount, set it to ImageBufferCount if that was large and set ImageBufferCount to 3
--
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'MaxImageBufferCount'
) > 0,
"SELECT 'Column MaxImageBufferCount already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `MaxImageBufferCount` smallint(5) unsigned NOT NULL default '0' AFTER `ImageBufferCount`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
UPDATE `Monitors` SET MaxImageBufferCount=ImageBufferCount WHERE ImageBufferCount >= 20;
UPDATE `Monitors` SET ImageBufferCount = 3;

View File

@ -28,7 +28,7 @@
%global _hardened_build 1 %global _hardened_build 1
Name: zoneminder Name: zoneminder
Version: 1.35.21 Version: 1.35.22
Release: 1%{?dist} Release: 1%{?dist}
Summary: A camera monitoring and analysis tool Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons Group: System Environment/Daemons

View File

@ -85,7 +85,7 @@ std::string load_monitor_sql =
"`RecordAudio`, " "`RecordAudio`, "
"`Brightness`, `Contrast`, `Hue`, `Colour`, " "`Brightness`, `Contrast`, `Hue`, `Colour`, "
"`EventPrefix`, `LabelFormat`, `LabelX`, `LabelY`, `LabelSize`," "`EventPrefix`, `LabelFormat`, `LabelX`, `LabelY`, `LabelSize`,"
"`ImageBufferCount`, `WarmupCount`, `PreEventCount`, `PostEventCount`, `StreamReplayBuffer`, `AlarmFrameCount`, " "`ImageBufferCount`, `MaxImageBufferCount`, `WarmupCount`, `PreEventCount`, `PostEventCount`, `StreamReplayBuffer`, `AlarmFrameCount`, "
"`SectionLength`, `MinSectionLength`, `FrameSkip`, `MotionFrameSkip`, " "`SectionLength`, `MinSectionLength`, `FrameSkip`, `MotionFrameSkip`, "
"`FPSReportInterval`, `RefBlendPerc`, `AlarmRefBlendPerc`, `TrackMotion`, `Exif`," "`FPSReportInterval`, `RefBlendPerc`, `AlarmRefBlendPerc`, `TrackMotion`, `Exif`,"
"`RTSPServer`, `RTSPStreamName`," "`RTSPServer`, `RTSPStreamName`,"
@ -327,6 +327,7 @@ Monitor::Monitor()
label_coord(Coord(0,0)), label_coord(Coord(0,0)),
label_size(0), label_size(0),
image_buffer_count(0), image_buffer_count(0),
max_image_buffer_count(0),
warmup_count(0), warmup_count(0),
pre_event_count(0), pre_event_count(0),
post_event_count(0), post_event_count(0),
@ -431,7 +432,7 @@ Monitor::Monitor()
"RecordAudio, " "RecordAudio, "
"Brightness, Contrast, Hue, Colour, " "Brightness, Contrast, Hue, Colour, "
"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize," "EventPrefix, LabelFormat, LabelX, LabelY, LabelSize,"
"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, " "ImageBufferCount, `MaxImageBufferCount`, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, "
"SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, " "SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, "
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif," "FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif,"
"`RTSPServer`,`RTSPStreamName`, "`RTSPServer`,`RTSPStreamName`,
@ -579,10 +580,14 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
label_size = atoi(dbrow[col]); col++; label_size = atoi(dbrow[col]); col++;
image_buffer_count = atoi(dbrow[col]); col++; image_buffer_count = atoi(dbrow[col]); col++;
max_image_buffer_count = atoi(dbrow[col]); col++;
warmup_count = atoi(dbrow[col]); col++; warmup_count = atoi(dbrow[col]); col++;
pre_event_count = atoi(dbrow[col]); col++; pre_event_count = atoi(dbrow[col]); col++;
packetqueue.setMaxVideoPackets(pre_event_count); packetqueue.setPreEventVideoPackets(pre_event_count);
packetqueue.setMaxVideoPackets(max_image_buffer_count);
packetqueue.setKeepKeyframes(videowriter == PASSTHROUGH); packetqueue.setKeepKeyframes(videowriter == PASSTHROUGH);
post_event_count = atoi(dbrow[col]); col++; post_event_count = atoi(dbrow[col]); col++;
stream_replay_buffer = atoi(dbrow[col]); col++; stream_replay_buffer = atoi(dbrow[col]); col++;
alarm_frame_count = atoi(dbrow[col]); col++; alarm_frame_count = atoi(dbrow[col]); col++;
@ -590,7 +595,6 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
alarm_frame_count = 1; alarm_frame_count = 1;
else if ( alarm_frame_count > MAX_PRE_ALARM_FRAMES ) else if ( alarm_frame_count > MAX_PRE_ALARM_FRAMES )
alarm_frame_count = MAX_PRE_ALARM_FRAMES; alarm_frame_count = MAX_PRE_ALARM_FRAMES;
pre_event_buffer_count = pre_event_count + alarm_frame_count + warmup_count - 1;
section_length = atoi(dbrow[col]); col++; section_length = atoi(dbrow[col]); col++;
min_section_length = atoi(dbrow[col]); col++; min_section_length = atoi(dbrow[col]); col++;
@ -639,9 +643,9 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
// Should maybe store this for later use // Should maybe store this for later use
std::string monitor_dir = stringtf("%s/%d", storage->Path(), id); std::string monitor_dir = stringtf("%s/%d", storage->Path(), id);
LoadCamera();
if ( purpose != QUERY ) { if ( purpose != QUERY ) {
LoadCamera();
Zone **zones = 0; Zone **zones = 0;
int n_zones = Zone::Load(this, zones); int n_zones = Zone::Load(this, zones);
this->AddZones(n_zones, zones); this->AddZones(n_zones, zones);
@ -676,7 +680,6 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
} }
} // end if purpose } // end if purpose
Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones); Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones);
} // Monitor::Load } // Monitor::Load
@ -3125,7 +3128,7 @@ int Monitor::PrimeCapture() {
} }
Debug(2, "Video stream id is %d, audio is %d, minimum_packets to keep in buffer %d", Debug(2, "Video stream id is %d, audio is %d, minimum_packets to keep in buffer %d",
video_stream_id, audio_stream_id, pre_event_buffer_count); video_stream_id, audio_stream_id, pre_event_count);
if (rtsp_server) { if (rtsp_server) {
if (video_stream_id >= 0) { if (video_stream_id >= 0) {

View File

@ -292,10 +292,9 @@ protected:
char label_format[64]; // The format of the timestamp on the images char label_format[64]; // The format of the timestamp on the images
Coord label_coord; // The coordinates of the timestamp on the images Coord label_coord; // The coordinates of the timestamp on the images
int label_size; // Size of the timestamp on the images int label_size; // Size of the timestamp on the images
int32_t image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count int32_t image_buffer_count; // Size of circular image buffer, kept in /dev/shm
int pre_event_buffer_count; // Size of dedicated circular pre event buffer used when analysis is not performed at capturing framerate, int32_t max_image_buffer_count; // Max # of video packets to keep in packet queue
// value is pre_event_count + alarm_frame_count - 1 int warmup_count; // How many images to process before looking for events
int warmup_count; // How many images to process before looking for events
int pre_event_count; // How many images to hold and prepend to an alarm event int pre_event_count; // How many images to hold and prepend to an alarm event
int post_event_count; // How many unalarmed images must occur before the alarm state is reset int post_event_count; // How many unalarmed images must occur before the alarm state is reset
int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now

View File

@ -29,6 +29,7 @@
PacketQueue::PacketQueue(): PacketQueue::PacketQueue():
video_stream_id(-1), video_stream_id(-1),
max_video_packet_count(-1), max_video_packet_count(-1),
pre_event_video_packet_count(-1),
max_stream_id(-1), max_stream_id(-1),
packet_counts(nullptr), packet_counts(nullptr),
deleting(false), deleting(false),
@ -84,26 +85,69 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) {
Debug(4, "No video keyframe so no one needs us to queue packets."); Debug(4, "No video keyframe so no one needs us to queue packets.");
return false; return false;
} }
mutex.lock(); {
std::unique_lock<std::mutex> lck(mutex);
pktQueue.push_back(add_packet); if (add_packet->packet.stream_index == video_stream_id) {
packet_counts[add_packet->packet.stream_index] += 1; if ((max_video_packet_count > 0) and (packet_counts[video_stream_id] > max_video_packet_count)) {
Debug(2, "packet counts for %d is %d", Warning("You have set the video packets in the queue to %d. The queue is full. Either Analysis is not keeping up or your camera's keyframe interval is larger than this setting. We are dropping packets.");
add_packet->packet.stream_index, if (add_packet->keyframe) {
packet_counts[add_packet->packet.stream_index]); // Have a new keyframe, so delete everything
while ((*pktQueue.begin() != add_packet) and (packet_counts[video_stream_id] > max_video_packet_count)) {
ZMPacket *zm_packet = *pktQueue.begin();
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
if (!lp->trylock()) {
Debug(1, "Found locked packet when trying to free up video packets. Can't continue");
//delete lp;
break;
}
delete lp;
for ( for (
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin(); std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
iterators_it != iterators.end(); iterators_it != iterators.end();
++iterators_it ++iterators_it
) { ) {
packetqueue_iterator *iterator_it = *iterators_it; packetqueue_iterator *iterator_it = *iterators_it;
if ( *iterator_it == pktQueue.end() ) { // Have to check each iterator and make sure it doesn't point to the packet we are about to delete
Debug(4, "pointing it %p to back", iterator_it); if ( *(*iterator_it) == zm_packet ) {
--(*iterator_it); Debug(1, "Bumping IT because it is at the front that we are deleting");
} ++(*iterators_it);
} // end foreach iterator }
mutex.unlock(); } // end foreach iterator
pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1;
Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d",
zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size());
delete zm_packet;
} // end while
}
} // end if too many video packets
if ((max_video_packet_count > 0) and (packet_counts[video_stream_id] > max_video_packet_count)) {
Error("Unable to free up older packets. Not queueing this video packet.");
return false;
}
} // end if this packet is a video packet
pktQueue.push_back(add_packet);
packet_counts[add_packet->packet.stream_index] += 1;
Debug(2, "packet counts for %d is %d",
add_packet->packet.stream_index,
packet_counts[add_packet->packet.stream_index]);
for (
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
iterators_it != iterators.end();
++iterators_it
) {
packetqueue_iterator *iterator_it = *iterators_it;
if ( *iterator_it == pktQueue.end() ) {
Debug(4, "pointing it %p to back", iterator_it);
--(*iterator_it);
}
} // end foreach iterator
} // end lock scope
// We signal on every packet because someday we may analyze sound // We signal on every packet because someday we may analyze sound
Debug(4, "packetqueue queuepacket, unlocked signalling"); Debug(4, "packetqueue queuepacket, unlocked signalling");
condition.notify_all(); condition.notify_all();
@ -126,13 +170,13 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
and and
add_packet->keyframe add_packet->keyframe
and and
(packet_counts[video_stream_id] > max_video_packet_count) (packet_counts[video_stream_id] > pre_event_video_packet_count)
and and
*(pktQueue.begin()) != add_packet *(pktQueue.begin()) != add_packet
) )
) { ) {
Debug(3, "stream index %d ?= video_stream_id %d, keyframe %d, keep_keyframes %d, counts %d > max %d at begin %d", Debug(3, "stream index %d ?= video_stream_id %d, keyframe %d, keep_keyframes %d, counts %d > pre_event_count %d at begin %d",
add_packet->packet.stream_index, video_stream_id, add_packet->keyframe, keep_keyframes, packet_counts[video_stream_id], max_video_packet_count, add_packet->packet.stream_index, video_stream_id, add_packet->keyframe, keep_keyframes, packet_counts[video_stream_id], pre_event_video_packet_count,
( *(pktQueue.begin()) != add_packet ) ( *(pktQueue.begin()) != add_packet )
); );
return; return;
@ -155,7 +199,7 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
if (!keep_keyframes) { if (!keep_keyframes) {
// If not doing passthrough, we don't care about starting with a keyframe so logic is simpler // If not doing passthrough, we don't care about starting with a keyframe so logic is simpler
while ((*pktQueue.begin() != add_packet) and (packet_counts[video_stream_id] > max_video_packet_count + tail_count)) { while ((*pktQueue.begin() != add_packet) and (packet_counts[video_stream_id] > pre_event_video_packet_count + tail_count)) {
ZMPacket *zm_packet = *pktQueue.begin(); ZMPacket *zm_packet = *pktQueue.begin();
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet); ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
if (!lp->trylock()) break; if (!lp->trylock()) break;
@ -164,7 +208,7 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
pktQueue.pop_front(); pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1; packet_counts[zm_packet->packet.stream_index] -= 1;
Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d", Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d",
zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size()); zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], pre_event_video_packet_count, pktQueue.size());
delete zm_packet; delete zm_packet;
} // end while } // end while
return; return;
@ -201,7 +245,7 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
++video_packets_to_delete; ++video_packets_to_delete;
Debug(4, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d", Debug(4, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d",
video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count); video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count);
if (packet_counts[video_stream_id] - video_packets_to_delete <= max_video_packet_count + tail_count) { if (packet_counts[video_stream_id] - video_packets_to_delete <= pre_event_video_packet_count + tail_count) {
break; break;
} }
} }
@ -221,7 +265,7 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
} }
Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d", Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d",
zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size()); zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], pre_event_video_packet_count, pktQueue.size());
pktQueue.pop_front(); pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1; packet_counts[zm_packet->packet.stream_index] -= 1;
delete zm_packet; delete zm_packet;
@ -238,7 +282,7 @@ ZMLockedPacket* PacketQueue::popPacket( ) {
return nullptr; return nullptr;
} }
Debug(4, "poPacket Mutex locking"); Debug(4, "poPacket Mutex locking");
mutex.lock(); std::unique_lock<std::mutex> lck(mutex);
ZMPacket *zm_packet = pktQueue.front(); ZMPacket *zm_packet = pktQueue.front();
for ( for (
@ -260,8 +304,6 @@ ZMLockedPacket* PacketQueue::popPacket( ) {
pktQueue.pop_front(); pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1; packet_counts[zm_packet->packet.stream_index] -= 1;
mutex.unlock();
return lp; return lp;
} // popPacket } // popPacket
@ -285,7 +327,7 @@ unsigned int PacketQueue::clear(unsigned int frames_to_keep, int stream_id) {
return 0; return 0;
} }
Debug(5, "Locking in clear"); Debug(5, "Locking in clear");
mutex.lock(); std::unique_lock<std::mutex> lck(mutex);
packetqueue_iterator it = pktQueue.end()--; // point to last element instead of end packetqueue_iterator it = pktQueue.end()--; // point to last element instead of end
ZMPacket *zm_packet = nullptr; ZMPacket *zm_packet = nullptr;
@ -340,13 +382,7 @@ unsigned int PacketQueue::clear(unsigned int frames_to_keep, int stream_id) {
delete_count += 1; delete_count += 1;
} // while our iterator is not the first packet } // while our iterator is not the first packet
zm_packet = nullptr; // tidy up for valgrind
Debug(3, "Deleted %d packets, %d remaining", delete_count, pktQueue.size()); Debug(3, "Deleted %d packets, %d remaining", delete_count, pktQueue.size());
mutex.unlock();
return delete_count;
Debug(3, "Deleted packets, resulting size is %d", pktQueue.size());
mutex.unlock();
return delete_count; return delete_count;
} // end unsigned int PacketQueue::clear( unsigned int frames_to_keep, int stream_id ) } // end unsigned int PacketQueue::clear( unsigned int frames_to_keep, int stream_id )
@ -389,7 +425,7 @@ unsigned int PacketQueue::clear(struct timeval *duration, int streamId) {
return 0; return 0;
} }
Debug(4, "Locking in clear"); Debug(4, "Locking in clear");
mutex.lock(); std::unique_lock<std::mutex> lck(mutex);
struct timeval keep_from; struct timeval keep_from;
std::list<ZMPacket *>::reverse_iterator it = pktQueue.rbegin(); std::list<ZMPacket *>::reverse_iterator it = pktQueue.rbegin();
@ -440,7 +476,6 @@ unsigned int PacketQueue::clear(struct timeval *duration, int streamId) {
} }
if ( it == pktQueue.rend() ) { if ( it == pktQueue.rend() ) {
Debug(1, "Didn't find a keyframe before event starttime. keeping all" ); Debug(1, "Didn't find a keyframe before event starttime. keeping all" );
mutex.unlock();
return 0; return 0;
} }
@ -462,14 +497,10 @@ unsigned int PacketQueue::clear(struct timeval *duration, int streamId) {
} // end foreach iterator } // end foreach iterator
pktQueue.pop_front(); pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1; packet_counts[zm_packet->packet.stream_index] -= 1;
//if ( zm_packet->image_index == -1 ) delete zm_packet;
delete zm_packet;
deleted_frames += 1; deleted_frames += 1;
} }
zm_packet = nullptr;
Debug(3, "Deleted %d frames", deleted_frames); Debug(3, "Deleted %d frames", deleted_frames);
mutex.unlock();
return deleted_frames; return deleted_frames;
} }
@ -706,7 +737,13 @@ bool PacketQueue::is_there_an_iterator_pointing_to_packet(ZMPacket *zm_packet) {
void PacketQueue::setMaxVideoPackets(int p) { void PacketQueue::setMaxVideoPackets(int p) {
max_video_packet_count = p; max_video_packet_count = p;
Debug(1, "Setting max_video_packet_count to %d", p); Debug(1, "Setting max_video_packet_count to %d", p);
if ( max_video_packet_count < 1 ) if ( max_video_packet_count < 0 )
max_video_packet_count = 1 ; max_video_packet_count = 0 ;
}
void PacketQueue::setPreEventVideoPackets(int p) {
pre_event_video_packet_count = p;
Debug(1, "Setting pre_event_video_packet_count to %d", p);
if ( pre_event_video_packet_count < 1 )
pre_event_video_packet_count = 1;
// We can simplify a lot of logic in queuePacket if we can assume at least 1 packet in queue // We can simplify a lot of logic in queuePacket if we can assume at least 1 packet in queue
} }

View File

@ -35,6 +35,8 @@ class PacketQueue {
int video_stream_id; int video_stream_id;
int max_video_packet_count; // allow a negative value to someday mean unlimited int max_video_packet_count; // allow a negative value to someday mean unlimited
// This is now a hard limit on the # of video packets to keep in the queue so that we can limit ram
int pre_event_video_packet_count; // Was max_video_packet_count
int max_stream_id; int max_stream_id;
int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */ int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */
bool deleting; bool deleting;
@ -52,6 +54,7 @@ class PacketQueue {
int addStream(); int addStream();
void setMaxVideoPackets(int p); void setMaxVideoPackets(int p);
void setPreEventVideoPackets(int p);
void setKeepKeyframes(bool k) { keep_keyframes = k; }; void setKeepKeyframes(bool k) { keep_keyframes = k; };
bool queuePacket(ZMPacket* packet); bool queuePacket(ZMPacket* packet);

View File

@ -1 +1 @@
1.35.21 1.35.22

View File

@ -84,6 +84,7 @@ class Monitor extends ZM_Object {
'LabelY' => 0, 'LabelY' => 0,
'LabelSize' => 1, 'LabelSize' => 1,
'ImageBufferCount' => 3, 'ImageBufferCount' => 3,
'MaxImageBufferCount' => 0,
'WarmupCount' => 0, 'WarmupCount' => 0,
'PreEventCount' => 5, 'PreEventCount' => 5,
'PostEventCount' => 5, 'PostEventCount' => 5,

View File

@ -441,6 +441,7 @@ $SLANG = array(
'Idle' => 'Idle', 'Idle' => 'Idle',
'Ignore' => 'Ignore', 'Ignore' => 'Ignore',
'ImageBufferSize' => 'Image Buffer Size (frames)', 'ImageBufferSize' => 'Image Buffer Size (frames)',
'MaxImageBufferCount' => 'Maximum Image Buffer Size (frames)',
'Image' => 'Image', 'Image' => 'Image',
'Images' => 'Images', 'Images' => 'Images',
'Include' => 'Include', 'Include' => 'Include',
@ -1137,6 +1138,19 @@ $OLANG = array(
optionally choose to not decode the H264/H265 packets. This will drastically reduce cpu use optionally choose to not decode the H264/H265 packets. This will drastically reduce cpu use
but will make live view unavailable for this monitor.' but will make live view unavailable for this monitor.'
), ),
'ImageBufferCount' => array(
'Help' => '
Number of raw images available in /dev/shm. Currently should be set in the 3-5 range. Used for live viewing.'
),
'MaxImageBufferCount' => array(
'Help' => '
Maximum number of video packets that will be held in the packet queue.
The packetqueue will normally manage itself, keeping Pre Event Count frames or all since last keyframe if using
passthrough mode. You can set a maximum to prevent the monitor from consuming too much ram, but your events might
not have all the frames they should if your keyframe interval is larger than this value.
You will get errors in your logs about this. So make sure your keyframe interval is low or you have enough ram.
'
),
// 'LANG_DEFAULT' => array( // 'LANG_DEFAULT' => array(
// 'Prompt' => "This is a new prompt for this option", // 'Prompt' => "This is a new prompt for this option",

View File

@ -29,6 +29,7 @@ input[name="newMonitor[Refresh]"],
input[name="newMonitor[LabelX]"], input[name="newMonitor[LabelX]"],
input[name="newMonitor[LabelY]"], input[name="newMonitor[LabelY]"],
input[name="newMonitor[ImageBufferCount]"], input[name="newMonitor[ImageBufferCount]"],
input[name="newMonitor[MaxImageBufferCount]"],
input[name="newMonitor[WarmupCount]"], input[name="newMonitor[WarmupCount]"],
input[name="newMonitor[PreEventCount]"], input[name="newMonitor[PreEventCount]"],
input[name="newMonitor[PostEventCount]"], input[name="newMonitor[PostEventCount]"],

View File

@ -48,7 +48,6 @@ function updateMonitorDimensions(element) {
form.elements['newMonitor[Height]'].value = dimensions[1]; form.elements['newMonitor[Height]'].value = dimensions[1];
} }
} }
update_estimated_ram_use();
return false; return false;
} }
@ -140,9 +139,6 @@ function initPage() {
form.submit(); form.submit();
}; };
}); });
document.querySelectorAll('input[name="newMonitor[ImageBufferCount]"],input[name="newMonitor[Width]"],input[name="newMonitor[Height]"]').forEach(function(el) {
el.oninput = window['update_estimated_ram_use'].bind(el);
});
document.querySelectorAll('select[name="newMonitor[Function]"]').forEach(function(el) { document.querySelectorAll('select[name="newMonitor[Function]"]').forEach(function(el) {
el.onchange = function() { el.onchange = function() {
@ -269,15 +265,6 @@ function random_WebColour() {
); );
} }
function update_estimated_ram_use() {
var buffer_count = document.querySelectorAll('input[name="newMonitor[ImageBufferCount]"]')[0].value;
var width = document.querySelectorAll('input[name="newMonitor[Width]"]')[0].value;
var height = document.querySelectorAll('input[name="newMonitor[Height]"]')[0].value;
var colours = document.querySelectorAll('select[name="newMonitor[Colours]"]')[0].value;
document.getElementById('estimated_ram_use').innerHTML = human_filesize(buffer_count * width * height * colours, 0);
}
function updateLatitudeAndLongitude(latitude, longitude) { function updateLatitudeAndLongitude(latitude, longitude) {
var form = document.getElementById('contentForm'); var form = document.getElementById('contentForm');
form.elements['newMonitor[Latitude]'].value = latitude; form.elements['newMonitor[Latitude]'].value = latitude;

View File

@ -1059,9 +1059,13 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor
{ {
?> ?>
<tr> <tr>
<td class="text-right pr-3"><?php echo translate('ImageBufferSize') ?></td> <td class="text-right pr-3"><?php echo translate('ImageBufferSize'); echo makeHelpLink('ImageBufferCount'); ?></td>
<td><input type="number" name="newMonitor[ImageBufferCount]" value="<?php echo validHtmlStr($monitor->ImageBufferCount()) ?>" min="1"/></td> <td><input type="number" name="newMonitor[ImageBufferCount]" value="<?php echo validHtmlStr($monitor->ImageBufferCount()) ?>" min="1"/></td>
</tr> </tr>
<tr>
<td class="text-right pr-3"><?php echo translate('MaxImageBufferCount'); echo makeHelpLink('MaxImageBufferCount'); ?></td>
<td><input type="number" name="newMonitor[MaxImageBufferCount]" value="<?php echo validHtmlStr($monitor->MaxImageBufferCount()) ?>" min="0"/></td>
</tr>
<tr> <tr>
<td class="text-right pr-3"><?php echo translate('WarmupFrames') ?></td> <td class="text-right pr-3"><?php echo translate('WarmupFrames') ?></td>
<td><input type="number" name="newMonitor[WarmupCount]" value="<?php echo validHtmlStr($monitor->WarmupCount()) ?>" min="0"/></td> <td><input type="number" name="newMonitor[WarmupCount]" value="<?php echo validHtmlStr($monitor->WarmupCount()) ?>" min="0"/></td>
@ -1082,10 +1086,6 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor
<td class="text-right pr-3"><?php echo translate('AlarmFrameCount') ?></td> <td class="text-right pr-3"><?php echo translate('AlarmFrameCount') ?></td>
<td><input type="number" name="newMonitor[AlarmFrameCount]" value="<?php echo validHtmlStr($monitor->AlarmFrameCount()) ?>" min="1"/></td> <td><input type="number" name="newMonitor[AlarmFrameCount]" value="<?php echo validHtmlStr($monitor->AlarmFrameCount()) ?>" min="1"/></td>
</tr> </tr>
<tr>
<td class="text-right pr-3"><?php echo translate('Estimated Ram Use') ?></td>
<td id="estimated_ram_use"><?php echo human_filesize($monitor->ImageBufferCount() * $monitor->Width() * $monitor->Height() * $monitor->Colours(), 0) ?></td>
</tr>
<?php <?php
break; break;
} }