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; int ret;
struct timeval video_buffer_duration = monitor->GetVideoBufferDuration();
int frameComplete = false; int frameComplete = false;
while ( !frameComplete ) { while ( !frameComplete ) {
av_init_packet(&packet); av_init_packet(&packet);
@ -920,6 +922,13 @@ int FfmpegCamera::CaptureAndRecord(
if ( packet.stream_index == mVideoStreamId ) { if ( packet.stream_index == mVideoStreamId ) {
if ( keyframe ) { if ( keyframe ) {
Debug(3, "Clearing queue"); 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 ( if (
packetqueue->packet_count(mVideoStreamId) packetqueue->packet_count(mVideoStreamId)
>= >=
@ -933,7 +942,6 @@ int FfmpegCamera::CaptureAndRecord(
packetqueue->packet_count(mVideoStreamId)+1); packetqueue->packet_count(mVideoStreamId)+1);
} }
packetqueue->clearQueue(monitor->GetPreEventCount(), mVideoStreamId);
packetqueue->queuePacket(&packet); packetqueue->queuePacket(&packet);
} else if ( packetqueue->size() ) { } else if ( packetqueue->size() ) {
// it's a keyframe or we already have something in the queue // 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 ), warmup_count( p_warmup_count ),
pre_event_count( p_pre_event_count ), pre_event_count( p_pre_event_count ),
post_event_count( p_post_event_count ), post_event_count( p_post_event_count ),
video_buffer_duration({0}),
stream_replay_buffer( p_stream_replay_buffer ), stream_replay_buffer( p_stream_replay_buffer ),
section_length( p_section_length ), section_length( p_section_length ),
min_section_length( p_min_section_length ), min_section_length( p_min_section_length ),
@ -368,6 +369,12 @@ Monitor::Monitor(
privacy_bitmask( NULL ), privacy_bitmask( NULL ),
event_delete_thread(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(name, p_name, sizeof(name)-1);
strncpy(event_prefix, p_event_prefix, sizeof(event_prefix)-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 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
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 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 section_length; // How long events should last in continuous modes
int min_section_length; // Minimum event length when using event_close_mode == ALARM int min_section_length; // Minimum event length when using event_close_mode == ALARM
@ -467,7 +468,8 @@ public:
void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; } void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; }
unsigned int GetPreEventCount() const { return pre_event_count; }; unsigned int GetPreEventCount() const { return pre_event_count; };
int GetImageBufferCount() const { return image_buffer_count; }; struct timeval GetVideoBufferDuration() const { return video_buffer_duration; };
int GetImageBufferCount() const { return image_buffer_count; };
State GetState() const; State GetState() const;
int GetImage( int index=-1, int scale=100 ); int GetImage( int index=-1, int scale=100 );
Snapshot *getSnapshot() const; Snapshot *getSnapshot() const;

View File

@ -204,6 +204,72 @@ void zm_packetqueue::clearQueue() {
Debug(3, "Deleted (%d) packets", delete_count ); 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() { unsigned int zm_packetqueue::size() {
return pktQueue.size(); return pktQueue.size();
} }

View File

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