2017-05-17 00:04:56 +08:00
//ZoneMinder Packet Queue Implementation Class
//Copyright 2016 Steve Gilvarry
//
//This file is part of ZoneMinder.
//
//ZoneMinder is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//ZoneMinder is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with ZoneMinder. If not, see <http://www.gnu.org/licenses/>.
# include "zm_packetqueue.h"
# include "zm_ffmpeg.h"
2017-08-24 03:05:44 +08:00
# include <sys/time.h>
2017-05-17 00:04:56 +08:00
# define VIDEO_QUEUESIZE 200
# define AUDIO_QUEUESIZE 50
2017-11-22 08:55:40 +08:00
zm_packetqueue : : zm_packetqueue ( ) {
2017-11-22 00:58:15 +08:00
video_packet_count = 0 ;
2017-05-17 00:04:56 +08:00
}
zm_packetqueue : : ~ zm_packetqueue ( ) {
2017-08-01 03:49:27 +08:00
clearQueue ( ) ;
2017-05-17 00:04:56 +08:00
}
bool zm_packetqueue : : queuePacket ( ZMPacket * zm_packet ) {
pktQueue . push_back ( zm_packet ) ;
2017-11-22 00:58:15 +08:00
if ( zm_packet - > codec_type = = AVMEDIA_TYPE_VIDEO )
video_packet_count + = 1 ;
2017-05-17 00:04:56 +08:00
return true ;
}
ZMPacket * zm_packetqueue : : popPacket ( ) {
if ( pktQueue . empty ( ) ) {
return NULL ;
}
ZMPacket * packet = pktQueue . front ( ) ;
pktQueue . pop_front ( ) ;
2017-11-22 08:55:40 +08:00
if ( packet - > codec_type = = AVMEDIA_TYPE_VIDEO )
2017-11-22 00:58:15 +08:00
video_packet_count - = 1 ;
2017-05-17 00:04:56 +08:00
return packet ;
}
unsigned int zm_packetqueue : : clearQueue ( unsigned int frames_to_keep , int stream_id ) {
2017-06-01 08:44:43 +08:00
Debug ( 3 , " Clearing all but %d frames, queue has %d " , frames_to_keep , pktQueue . size ( ) ) ;
2017-05-17 00:04:56 +08:00
frames_to_keep + = 1 ;
if ( pktQueue . empty ( ) ) {
Debug ( 3 , " Queue is empty " ) ;
return 0 ;
}
2017-08-24 03:05:44 +08:00
std : : list < ZMPacket * > : : reverse_iterator it ;
2017-05-17 00:04:56 +08:00
ZMPacket * packet = NULL ;
for ( it = pktQueue . rbegin ( ) ; it ! = pktQueue . rend ( ) & & frames_to_keep ; + + it ) {
ZMPacket * zm_packet = * it ;
AVPacket * av_packet = & ( zm_packet - > packet ) ;
2017-11-28 00:28:36 +08:00
Debug ( 4 , " Looking at packet with stream index (%d) with keyframe(%d), frames_to_keep is (%d) " ,
av_packet - > stream_index , ( av_packet - > flags & AV_PKT_FLAG_KEY ) , frames_to_keep ) ;
2017-05-17 00:04:56 +08:00
2017-11-22 00:58:15 +08:00
// Want frames_to_keep video frames. Otherwise, we may not have enough
if ( av_packet - > stream_index = = stream_id ) {
2017-05-17 00:04:56 +08:00
frames_to_keep - - ;
}
}
2017-11-22 00:58:15 +08:00
// Might not be starting with a keyframe, but should always start with a keyframe
2017-06-01 08:44:43 +08:00
if ( frames_to_keep ) {
2017-11-28 03:57:24 +08:00
Debug ( 4 , " Hit end of queue, still need (%d) video keyframes " , frames_to_keep ) ;
2017-11-22 00:58:15 +08:00
} else {
2017-11-23 21:40:49 +08:00
if ( it ! = pktQueue . rend ( ) ) {
2017-11-28 03:57:24 +08:00
Debug ( 4 , " Not rend " ) ;
2017-11-23 21:40:49 +08:00
2017-11-28 00:28:36 +08:00
ZMPacket * zm_packet = * it ;
2017-11-28 03:57:24 +08:00
Debug ( 4 , " packet %x %d " , zm_packet , zm_packet - > image_index ) ;
2017-11-28 00:28:36 +08:00
AVPacket * av_packet = & ( zm_packet - > packet ) ;
while (
( it ! = pktQueue . rend ( ) )
& &
( ( av_packet - > stream_index ! = stream_id ) | | ! ( av_packet - > flags & AV_PKT_FLAG_KEY ) )
) {
zm_packet = * it ;
2017-11-28 03:57:24 +08:00
Debug ( 4 , " packet %x %d " , zm_packet , zm_packet - > image_index ) ;
2017-11-28 00:28:36 +08:00
+ + it ;
av_packet = & ( ( * it ) - > packet ) ;
}
2017-11-22 00:58:15 +08:00
}
2017-06-01 08:44:43 +08:00
}
2017-05-17 00:04:56 +08:00
unsigned int delete_count = 0 ;
2017-11-28 00:28:36 +08:00
Debug ( 4 , " Deleting packets from the front, count is (%d) " , delete_count ) ;
2017-05-17 00:04:56 +08:00
while ( it ! = pktQueue . rend ( ) ) {
2017-06-01 08:44:43 +08:00
Debug ( 4 , " Deleting a packet from the front, count is (%d) " , delete_count ) ;
2017-05-17 00:04:56 +08:00
packet = pktQueue . front ( ) ;
2017-11-22 00:58:15 +08:00
if ( packet - > codec_type = = AVMEDIA_TYPE_VIDEO )
video_packet_count - = 1 ;
2017-05-17 00:04:56 +08:00
pktQueue . pop_front ( ) ;
2017-11-28 00:28:36 +08:00
if ( packet - > image_index = = - 1 )
2017-11-23 21:40:49 +08:00
delete packet ;
2017-05-17 00:04:56 +08:00
delete_count + = 1 ;
}
2017-06-01 08:44:43 +08:00
Debug ( 3 , " Deleted (%d) packets " , delete_count ) ;
2017-05-17 00:04:56 +08:00
return delete_count ;
} // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id )
void zm_packetqueue : : clearQueue ( ) {
ZMPacket * packet = NULL ;
while ( ! pktQueue . empty ( ) ) {
packet = pktQueue . front ( ) ;
pktQueue . pop_front ( ) ;
2017-11-28 00:28:36 +08:00
if ( packet - > image_index = = - 1 )
delete packet ;
2017-05-17 00:04:56 +08:00
}
2017-11-22 00:58:15 +08:00
video_packet_count = 0 ;
2017-05-17 00:04:56 +08:00
}
unsigned int zm_packetqueue : : size ( ) {
return pktQueue . size ( ) ;
}
2017-11-22 08:55:40 +08:00
unsigned int zm_packetqueue : : get_video_packet_count ( ) {
2017-11-22 00:58:15 +08:00
return video_packet_count ;
}
2017-05-17 00:04:56 +08:00
void zm_packetqueue : : clear_unwanted_packets ( timeval * recording_started , int mVideoStreamId ) {
// Need to find the keyframe <= recording_started. Can get rid of audio packets.
if ( pktQueue . empty ( ) ) {
return ;
}
// Step 1 - find keyframe < recording_started.
// Step 2 - pop packets until we get to the packet in step 2
2017-08-24 03:05:44 +08:00
std : : list < ZMPacket * > : : reverse_iterator it ;
2017-05-17 00:04:56 +08:00
2017-06-01 08:44:43 +08:00
Debug ( 3 , " Looking for keyframe after start recording stream id (%d) " , mVideoStreamId ) ;
2017-05-17 00:04:56 +08:00
for ( it = pktQueue . rbegin ( ) ; 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 = = mVideoStreamId )
& &
2017-11-22 08:55:40 +08:00
timercmp ( zm_packet - > timestamp , recording_started , < )
2017-05-17 00:04:56 +08:00
) {
2017-06-01 08:44:43 +08:00
Debug ( 3 , " Found keyframe before start with stream index (%d) with keyframe (%d) " , av_packet - > stream_index , ( av_packet - > flags & AV_PKT_FLAG_KEY ) ) ;
2017-05-17 00:04:56 +08:00
break ;
}
}
if ( it = = pktQueue . rend ( ) ) {
Debug ( 1 , " Didn't find a keyframe packet keeping all " ) ;
return ;
}
2017-06-01 08:44:43 +08:00
ZMPacket * zm_packet = * it ;
AVPacket * av_packet = & ( zm_packet - > packet ) ;
Debug ( 3 , " Found packet before start with stream index (%d) with keyframe (%d), distance(%d), size(%d) " ,
av_packet - > stream_index ,
( av_packet - > flags & AV_PKT_FLAG_KEY ) ,
distance ( it , pktQueue . rend ( ) ) ,
pktQueue . size ( ) ) ;
unsigned int deleted_frames = 0 ;
2017-05-17 00:04:56 +08:00
ZMPacket * packet = NULL ;
2017-06-01 08:44:43 +08:00
while ( distance ( it , pktQueue . rend ( ) ) > 1 ) {
//while ( pktQueue.rend() != it ) {
2017-05-17 00:04:56 +08:00
packet = pktQueue . front ( ) ;
pktQueue . pop_front ( ) ;
2017-11-28 00:28:36 +08:00
if ( packet - > image_index = = - 1 )
delete packet ;
2017-06-01 08:44:43 +08:00
deleted_frames + = 1 ;
}
zm_packet = pktQueue . front ( ) ;
av_packet = & ( zm_packet - > packet ) ;
if ( ( ! ( av_packet - > flags & AV_PKT_FLAG_KEY ) ) | | ( av_packet - > stream_index ! = mVideoStreamId ) ) {
Error ( " Done looking for keyframe. Deleted %d frames. Remaining frames in queue: %d stream of head packet is (%d), keyframe (%d), distance(%d), packets(%d) " , deleted_frames , pktQueue . size ( ) , av_packet - > stream_index , ( av_packet - > flags & AV_PKT_FLAG_KEY ) , distance ( it , pktQueue . rend ( ) ) , pktQueue . size ( ) ) ;
} else {
Debug ( 1 , " Done looking for keyframe. Deleted %d frames. Remaining frames in queue: %d stream of head packet is (%d), keyframe (%d), distance(%d), packets(%d) " , deleted_frames , pktQueue . size ( ) , av_packet - > stream_index , ( av_packet - > flags & AV_PKT_FLAG_KEY ) , distance ( it , pktQueue . rend ( ) ) , pktQueue . size ( ) ) ;
2017-05-17 00:04:56 +08:00
}
}