Properly compute video buffer length when analysis fps is set

Currently the number of video frames kept in the buffer is set as the
pre_event_count. This falls short when the capture fps is larger
than the analysis fps. Fix by computing the retained video duration
as pre_event_count/analysis_fps

No change if analysis fps is not set.

Signed-off-by: Selva Nair <selva.nair@gmail.com>
This commit is contained in:
Selva Nair 2019-11-01 17:29:55 -04:00
parent c3250dea00
commit 2e7fad68d1
5 changed files with 86 additions and 2 deletions

View File

@ -744,6 +744,8 @@ int FfmpegCamera::CaptureAndRecord(
}
int ret;
struct timeval video_buffer_duration = monitor->GetVideoBufferDuration();
int frameComplete = false;
while ( !frameComplete ) {
av_init_packet(&packet);
@ -920,6 +922,13 @@ int FfmpegCamera::CaptureAndRecord(
if ( packet.stream_index == mVideoStreamId ) {
if ( keyframe ) {
Debug(3, "Clearing queue");
if (video_buffer_duration.tv_sec > 0 || video_buffer_duration.tv_usec > 0) {
packetqueue->clearQueue(&video_buffer_duration, mVideoStreamId);
}
else {
packetqueue->clearQueue(monitor->GetPreEventCount(), mVideoStreamId);
}
if (
packetqueue->packet_count(mVideoStreamId)
>=
@ -933,7 +942,6 @@ int FfmpegCamera::CaptureAndRecord(
packetqueue->packet_count(mVideoStreamId)+1);
}
packetqueue->clearQueue(monitor->GetPreEventCount(), mVideoStreamId);
packetqueue->queuePacket(&packet);
} else if ( packetqueue->size() ) {
// it's a keyframe or we already have something in the queue

View File

@ -338,6 +338,7 @@ Monitor::Monitor(
warmup_count( p_warmup_count ),
pre_event_count( p_pre_event_count ),
post_event_count( p_post_event_count ),
video_buffer_duration({0}),
stream_replay_buffer( p_stream_replay_buffer ),
section_length( p_section_length ),
min_section_length( p_min_section_length ),
@ -368,6 +369,12 @@ Monitor::Monitor(
privacy_bitmask( NULL ),
event_delete_thread(NULL)
{
if (analysis_fps > 0.0) {
uint64_t usec = round(1000000*pre_event_count/analysis_fps);
video_buffer_duration.tv_sec = usec/1000000;
video_buffer_duration.tv_usec = usec % 1000000;
}
strncpy(name, p_name, sizeof(name)-1);
strncpy(event_prefix, p_event_prefix, sizeof(event_prefix)-1);

View File

@ -273,6 +273,7 @@ protected:
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 post_event_count; // How many unalarmed images must occur before the alarm state is reset
struct timeval video_buffer_duration; // How long a video segment to keep in buffer (set only if analysis fps != 0 )
int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now
int section_length; // How long events should last in continuous modes
int min_section_length; // Minimum event length when using event_close_mode == ALARM
@ -467,6 +468,7 @@ public:
void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; }
unsigned int GetPreEventCount() const { return pre_event_count; };
struct timeval GetVideoBufferDuration() const { return video_buffer_duration; };
int GetImageBufferCount() const { return image_buffer_count; };
State GetState() const;
int GetImage( int index=-1, int scale=100 );

View File

@ -204,6 +204,72 @@ void zm_packetqueue::clearQueue() {
Debug(3, "Deleted (%d) packets", delete_count );
}
// clear queue keeping only specified duration of video -- return number of pkts removed
unsigned int zm_packetqueue::clearQueue(struct timeval *duration, int streamId) {
if (pktQueue.empty()) {
return 0;
}
struct timeval keep_from;
std::list<ZMPacket *>::reverse_iterator it;
it = pktQueue.rbegin();
timersub(&(*it)->timestamp, duration, &keep_from);
++it;
Debug(3, "Looking for frame before queue keep time with stream id (%d), queue has %d packets",
streamId, pktQueue.size());
for ( ; it != pktQueue.rend(); ++it) {
ZMPacket *zm_packet = *it;
AVPacket *av_packet = &(zm_packet->packet);
if (av_packet->stream_index == streamId
&& timercmp( &zm_packet->timestamp, &keep_from, <= )) {
Debug(3, "Found frame before keep time with stream index %d at %d.%d",
av_packet->stream_index,
zm_packet->timestamp.tv_sec,
zm_packet->timestamp.tv_usec);
break;
}
}
if (it == pktQueue.rend()) {
Debug(1, "Didn't find a frame before queue preserve time. keeping all");
return 0;
}
Debug(3, "Looking for keyframe");
for ( ; it != pktQueue.rend(); ++it) {
ZMPacket *zm_packet = *it;
AVPacket *av_packet = &(zm_packet->packet);
if (av_packet->flags & AV_PKT_FLAG_KEY
&& av_packet->stream_index == streamId) {
Debug(3, "Found keyframe before start with stream index %d at %d.%d",
av_packet->stream_index,
zm_packet->timestamp.tv_sec,
zm_packet->timestamp.tv_usec );
break;
}
}
if ( it == pktQueue.rend() ) {
Debug(1, "Didn't find a keyframe before event starttime. keeping all" );
return 0;
}
unsigned int deleted_frames = 0;
ZMPacket *zm_packet = NULL;
while (distance(it, pktQueue.rend()) > 1) {
zm_packet = pktQueue.front();
pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1;
delete zm_packet;
deleted_frames += 1;
}
zm_packet = NULL;
Debug(3, "Deleted %d frames", deleted_frames);
return deleted_frames;
}
unsigned int zm_packetqueue::size() {
return pktQueue.size();
}

View File

@ -40,6 +40,7 @@ public:
bool popVideoPacket(ZMPacket* packet);
bool popAudioPacket(ZMPacket* packet);
unsigned int clearQueue(unsigned int video_frames_to_keep, int stream_id);
unsigned int clearQueue(struct timeval *duration, int streamid);
void clearQueue();
void dumpQueue();
unsigned int size();