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/>.
|
|
|
|
|
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
// PacketQueue must know about all iterators and manage them
|
|
|
|
|
2017-05-17 00:04:56 +08:00
|
|
|
#include "zm_packetqueue.h"
|
|
|
|
#include "zm_ffmpeg.h"
|
2019-02-26 22:45:40 +08:00
|
|
|
#include "zm_signal.h"
|
2017-08-24 03:05:44 +08:00
|
|
|
#include <sys/time.h>
|
2019-06-24 23:27:47 +08:00
|
|
|
#include "zm_time.h"
|
2017-05-17 00:04:56 +08:00
|
|
|
|
2020-12-16 05:01:18 +08:00
|
|
|
zm_packetqueue::zm_packetqueue(
|
|
|
|
int video_image_count,
|
|
|
|
int p_video_stream_id,
|
|
|
|
int p_audio_stream_id
|
2020-12-22 23:20:44 +08:00
|
|
|
):
|
2020-12-30 01:18:26 +08:00
|
|
|
video_stream_id(p_video_stream_id),
|
|
|
|
max_video_packet_count(video_image_count),
|
2020-12-22 23:20:44 +08:00
|
|
|
deleting(false)
|
|
|
|
{
|
2018-10-21 05:31:14 +08:00
|
|
|
|
|
|
|
max_stream_id = p_video_stream_id > p_audio_stream_id ? p_video_stream_id : p_audio_stream_id;
|
2018-10-15 22:51:56 +08:00
|
|
|
packet_counts = new int[max_stream_id+1];
|
|
|
|
for ( int i=0; i <= max_stream_id; ++i )
|
2018-10-15 23:13:10 +08:00
|
|
|
packet_counts[i] = 0;
|
2017-05-17 00:04:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
zm_packetqueue::~zm_packetqueue() {
|
2020-12-10 04:01:24 +08:00
|
|
|
deleting = true;
|
2021-01-08 04:12:44 +08:00
|
|
|
|
|
|
|
// Anyone waiting should immediately check deleting
|
|
|
|
condition.notify_all();
|
2020-12-10 04:01:24 +08:00
|
|
|
/* zma might be waiting. Must have exclusive access */
|
2021-01-07 22:43:53 +08:00
|
|
|
while ( !mutex.try_lock() ) {
|
2020-12-16 05:01:18 +08:00
|
|
|
Debug(4, "Waiting for exclusive access");
|
2020-12-10 04:01:24 +08:00
|
|
|
condition.notify_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( !pktQueue.empty() ) {
|
2021-01-07 22:43:53 +08:00
|
|
|
ZMPacket *packet = pktQueue.front();
|
2020-12-10 04:01:24 +08:00
|
|
|
pktQueue.pop_front();
|
2021-01-07 22:43:53 +08:00
|
|
|
delete packet;
|
2020-12-10 04:01:24 +08:00
|
|
|
}
|
|
|
|
|
2018-10-15 22:51:56 +08:00
|
|
|
delete[] packet_counts;
|
2021-01-07 22:43:53 +08:00
|
|
|
Debug(4, "Done in destructor");
|
2020-08-26 07:45:48 +08:00
|
|
|
packet_counts = nullptr;
|
2020-12-10 04:01:24 +08:00
|
|
|
mutex.unlock();
|
2020-12-15 23:14:19 +08:00
|
|
|
condition.notify_all();
|
2017-05-17 00:04:56 +08:00
|
|
|
}
|
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
/* Enqueues the given packet. Will maintain the it pointer and image packet counts.
|
2018-08-18 04:06:03 +08:00
|
|
|
* If we have reached our max image packet count, it will pop off as many packets as are needed.
|
|
|
|
* Thus it will ensure that the same packet never gets queued twice.
|
|
|
|
*/
|
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
bool zm_packetqueue::queuePacket(ZMPacket* add_packet) {
|
2021-01-19 22:46:08 +08:00
|
|
|
Debug(4, "packetqueue queuepacket %p %d", add_packet, add_packet->image_index);
|
2019-02-25 23:21:43 +08:00
|
|
|
mutex.lock();
|
2017-12-08 23:39:24 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
pktQueue.push_back(add_packet);
|
|
|
|
packet_counts[add_packet->packet.stream_index] += 1;
|
2020-12-30 01:18:26 +08:00
|
|
|
Debug(1, "packet counts for %d is %d",
|
2021-01-07 22:43:53 +08:00
|
|
|
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() ) {
|
2021-01-08 04:12:44 +08:00
|
|
|
Debug(4, "pointing it %p to back", iterator_it);
|
2021-01-07 22:43:53 +08:00
|
|
|
--(*iterator_it);
|
|
|
|
}
|
|
|
|
} // end foreach iterator
|
|
|
|
|
|
|
|
// Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one.
|
|
|
|
// No good. Have to satisfy two conditions:
|
|
|
|
// 1. packetqueue starts with a video keyframe
|
|
|
|
// 2. Have minimum # of video packets
|
|
|
|
// 3. No packets can be locked
|
|
|
|
// 4. No iterator can point to one of the packets
|
|
|
|
//
|
|
|
|
// So start at the beginning, counting video packets until the next keyframe.
|
|
|
|
// Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them.
|
|
|
|
if ( add_packet->packet.stream_index == video_stream_id
|
|
|
|
and
|
|
|
|
add_packet->keyframe
|
|
|
|
and
|
|
|
|
(packet_counts[video_stream_id] > max_video_packet_count)
|
|
|
|
) {
|
|
|
|
packetqueue_iterator it = pktQueue.begin();
|
|
|
|
int video_stream_packets = 0;
|
|
|
|
// Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that
|
|
|
|
do {
|
|
|
|
it++;
|
|
|
|
ZMPacket *zm_packet = *it;
|
|
|
|
Debug(1, "Checking packet to see if we can delete them");
|
|
|
|
if ( zm_packet->packet.stream_index == video_stream_id ) {
|
2021-01-13 03:13:12 +08:00
|
|
|
if ( zm_packet->keyframe ) {
|
|
|
|
Debug(1, "Have a video keyframe so breaking out");
|
2021-01-26 01:07:56 +08:00
|
|
|
if ( !zm_packet->trylock() ) {
|
|
|
|
Debug(1, "Have locked packet %d", zm_packet->image_index);
|
|
|
|
video_stream_packets = max_video_packet_count;
|
|
|
|
}
|
|
|
|
zm_packet->unlock();
|
2021-01-07 22:43:53 +08:00
|
|
|
break;
|
2021-01-13 03:13:12 +08:00
|
|
|
}
|
2021-01-07 22:43:53 +08:00
|
|
|
video_stream_packets ++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !zm_packet->trylock() ) {
|
2021-01-08 04:12:44 +08:00
|
|
|
Debug(1, "Have locked packet %d", zm_packet->image_index);
|
2021-01-07 22:43:53 +08:00
|
|
|
video_stream_packets = max_video_packet_count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
zm_packet->unlock();
|
|
|
|
|
|
|
|
for (
|
|
|
|
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
|
|
|
iterators_it != iterators.end();
|
|
|
|
++iterators_it
|
|
|
|
) {
|
|
|
|
packetqueue_iterator *iterator_it = *iterators_it;
|
|
|
|
// Have to check each iterator and make sure it doesn't point to the packet we are about to delete
|
|
|
|
if ( *(*iterator_it) == zm_packet ) {
|
2021-01-19 22:46:08 +08:00
|
|
|
Debug(4, "Found IT at beginning of queue. Threads not keeping up");
|
2021-01-07 22:43:53 +08:00
|
|
|
video_stream_packets = max_video_packet_count;
|
|
|
|
}
|
|
|
|
} // end foreach iterator
|
|
|
|
|
2021-01-08 04:12:44 +08:00
|
|
|
} while ( *it != add_packet );
|
2021-01-19 22:46:08 +08:00
|
|
|
Debug(1, "Resulting video_stream_packets count %d, %d > %d, pointing at latest packet? %d",
|
2021-01-20 02:43:25 +08:00
|
|
|
video_stream_packets,
|
2021-01-08 04:12:44 +08:00
|
|
|
packet_counts[video_stream_id] - video_stream_packets, max_video_packet_count,
|
|
|
|
( *it == add_packet )
|
|
|
|
);
|
2021-01-07 22:43:53 +08:00
|
|
|
if (
|
2021-01-08 04:12:44 +08:00
|
|
|
packet_counts[video_stream_id] - video_stream_packets > max_video_packet_count
|
2021-01-07 22:43:53 +08:00
|
|
|
and
|
|
|
|
( *it != add_packet )
|
|
|
|
) {
|
|
|
|
Debug(1, "Deleting packets");
|
2021-01-13 03:13:12 +08:00
|
|
|
// It is enough to delete the packets tested above. A subsequent queuePacket can clear a second set
|
|
|
|
while ( pktQueue.begin() != it ) {
|
2021-01-07 22:43:53 +08:00
|
|
|
ZMPacket *zm_packet = *pktQueue.begin();
|
|
|
|
if ( !zm_packet ) {
|
|
|
|
Error("NULL zm_packet in queue");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-01-20 02:43:25 +08:00
|
|
|
Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d",
|
2021-01-13 03:13:12 +08:00
|
|
|
zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size());
|
2021-01-07 22:43:53 +08:00
|
|
|
pktQueue.pop_front();
|
|
|
|
packet_counts[zm_packet->packet.stream_index] -= 1;
|
|
|
|
delete zm_packet;
|
|
|
|
}
|
|
|
|
} // end if have at least max_video_packet_count video packets remaining
|
|
|
|
} // end if this is a video keyframe
|
2018-08-18 04:06:03 +08:00
|
|
|
|
2019-02-25 23:21:43 +08:00
|
|
|
mutex.unlock();
|
2020-12-10 04:01:24 +08:00
|
|
|
// We signal on every packet because someday we may analyze sound
|
2020-12-16 05:01:18 +08:00
|
|
|
Debug(4, "packetqueue queuepacket, unlocked signalling");
|
2020-12-10 04:01:24 +08:00
|
|
|
condition.notify_all();
|
2017-05-17 00:04:56 +08:00
|
|
|
|
|
|
|
return true;
|
2017-12-08 23:39:24 +08:00
|
|
|
} // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet)
|
2017-05-17 00:04:56 +08:00
|
|
|
|
|
|
|
ZMPacket* zm_packetqueue::popPacket( ) {
|
2020-12-16 05:01:18 +08:00
|
|
|
Debug(4, "pktQueue size %d", pktQueue.size());
|
2017-05-17 00:04:56 +08:00
|
|
|
if ( pktQueue.empty() ) {
|
2020-08-26 07:45:48 +08:00
|
|
|
return nullptr;
|
2017-05-17 00:04:56 +08:00
|
|
|
}
|
2020-12-16 05:01:18 +08:00
|
|
|
Debug(4, "poPacket Mutex locking");
|
2019-02-25 23:21:43 +08:00
|
|
|
mutex.lock();
|
2017-05-17 00:04:56 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
ZMPacket *zm_packet = pktQueue.front();
|
|
|
|
for (
|
|
|
|
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
|
|
|
iterators_it != iterators.end();
|
|
|
|
++iterators_it
|
|
|
|
) {
|
|
|
|
packetqueue_iterator *iterator_it = *iterators_it;
|
|
|
|
// Have to check each iterator and make sure it doesn't point to the packet we are about to delete
|
|
|
|
if ( *(*iterator_it) == zm_packet ) {
|
|
|
|
Debug(4, "Bumping it because it is at the front that we are deleting");
|
|
|
|
++(*iterators_it);
|
|
|
|
}
|
|
|
|
} // end foreach iterator
|
|
|
|
|
|
|
|
zm_packet->lock();
|
2017-12-01 03:37:36 +08:00
|
|
|
|
2017-05-17 00:04:56 +08:00
|
|
|
pktQueue.pop_front();
|
2021-01-07 22:43:53 +08:00
|
|
|
packet_counts[zm_packet->packet.stream_index] -= 1;
|
2020-12-22 23:20:44 +08:00
|
|
|
|
2019-02-25 23:21:43 +08:00
|
|
|
mutex.unlock();
|
2017-05-17 00:04:56 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
return zm_packet;
|
2020-12-10 04:01:24 +08:00
|
|
|
} // popPacket
|
2017-05-17 00:04:56 +08:00
|
|
|
|
2020-12-22 23:20:44 +08:00
|
|
|
|
|
|
|
/* Keeps frames_to_keep frames of the provided stream, which theoretically is the video stream
|
|
|
|
* Basically it starts at the end, moving backwards until it finds the minimum video frame.
|
|
|
|
* Then it should probably move forward to find a keyframe. The first video frame must always be a keyframe.
|
|
|
|
* So really frames_to_keep is a maximum which isn't so awesome.. maybe we should go back farther to find the keyframe in which case
|
|
|
|
* frames_to_keep in a minimum
|
|
|
|
*/
|
|
|
|
|
2018-10-15 22:51:56 +08:00
|
|
|
unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_id) {
|
2018-08-18 04:06:03 +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
|
|
|
|
|
|
|
if ( pktQueue.empty() ) {
|
|
|
|
return 0;
|
|
|
|
}
|
2020-12-22 23:20:44 +08:00
|
|
|
|
|
|
|
// If size is <= frames_to_keep since it could contain audio, we can't possibly do anything
|
2018-02-16 03:08:21 +08:00
|
|
|
if ( pktQueue.size() <= frames_to_keep ) {
|
|
|
|
return 0;
|
|
|
|
}
|
2021-01-07 22:43:53 +08:00
|
|
|
Debug(5, "Locking in clearQueue");
|
2019-02-25 23:21:43 +08:00
|
|
|
mutex.lock();
|
2020-12-22 23:20:44 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
packetqueue_iterator it = pktQueue.end()--; // point to last element instead of end
|
2020-12-22 23:20:44 +08:00
|
|
|
ZMPacket *zm_packet = nullptr;
|
|
|
|
|
|
|
|
while ( (it != pktQueue.begin()) and frames_to_keep ) {
|
|
|
|
zm_packet = *it;
|
|
|
|
AVPacket *av_packet = &(zm_packet->packet);
|
|
|
|
|
|
|
|
Debug(3, "Looking at packet with stream index (%d) with keyframe(%d), Image_index(%d) frames_to_keep is (%d)",
|
|
|
|
av_packet->stream_index, zm_packet->keyframe, zm_packet->image_index, frames_to_keep );
|
|
|
|
|
|
|
|
// Want frames_to_keep video keyframes. Otherwise, we may not have enough
|
|
|
|
if ( av_packet->stream_index == stream_id ) {
|
|
|
|
frames_to_keep --;
|
|
|
|
}
|
|
|
|
it --;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Either at beginning or frames_to_keep == 0
|
|
|
|
|
|
|
|
if ( it == pktQueue.begin() ) {
|
|
|
|
if ( frames_to_keep ) {
|
|
|
|
Warning("Couldn't remove any packets, needed %d", frames_to_keep);
|
|
|
|
}
|
|
|
|
mutex.unlock();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int delete_count = 0;
|
|
|
|
|
|
|
|
// Else not at beginning, are pointing at packet before the last video packet
|
|
|
|
while ( pktQueue.begin() != it ) {
|
|
|
|
Debug(4, "Deleting a packet from the front, count is (%d), queue size is %d",
|
|
|
|
delete_count, pktQueue.size());
|
|
|
|
zm_packet = pktQueue.front();
|
2021-01-07 22:43:53 +08:00
|
|
|
for (
|
|
|
|
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
|
|
|
iterators_it != iterators.end();
|
|
|
|
++iterators_it
|
|
|
|
) {
|
|
|
|
packetqueue_iterator *iterator_it = *iterators_it;
|
|
|
|
// Have to check each iterator and make sure it doesn't point to the packet we are about to delete
|
|
|
|
if ( *(*iterator_it) == zm_packet ) {
|
|
|
|
Debug(4, "Bumping it because it is at the front that we are deleting");
|
|
|
|
++(*iterators_it);
|
|
|
|
}
|
|
|
|
} // end foreach iterator
|
2020-12-22 23:20:44 +08:00
|
|
|
packet_counts[zm_packet->packet.stream_index] --;
|
|
|
|
pktQueue.pop_front();
|
2021-01-07 22:43:53 +08:00
|
|
|
//if ( zm_packet->image_index == -1 )
|
2020-12-22 23:20:44 +08:00
|
|
|
delete zm_packet;
|
|
|
|
|
|
|
|
delete_count += 1;
|
|
|
|
} // 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());
|
|
|
|
mutex.unlock();
|
|
|
|
return delete_count;
|
|
|
|
|
2018-08-18 04:06:03 +08:00
|
|
|
Debug(3, "Deleted packets, resulting size is %d", pktQueue.size());
|
2019-02-25 23:21:43 +08:00
|
|
|
mutex.unlock();
|
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() {
|
2020-12-16 05:01:18 +08:00
|
|
|
Debug(4, "Clocking in clearQueue");
|
2017-12-08 23:39:24 +08:00
|
|
|
mutex.lock();
|
2020-08-26 07:45:48 +08:00
|
|
|
ZMPacket *packet = nullptr;
|
2018-09-14 04:18:28 +08:00
|
|
|
int delete_count = 0;
|
2019-01-17 04:20:17 +08:00
|
|
|
while ( !pktQueue.empty() ) {
|
2017-05-17 00:04:56 +08:00
|
|
|
packet = pktQueue.front();
|
2018-10-15 22:51:56 +08:00
|
|
|
packet_counts[packet->packet.stream_index] -= 1;
|
2017-05-17 00:04:56 +08:00
|
|
|
pktQueue.pop_front();
|
2021-01-07 22:43:53 +08:00
|
|
|
//if ( packet->image_index == -1 )
|
2017-11-28 00:28:36 +08:00
|
|
|
delete packet;
|
2018-09-14 04:18:28 +08:00
|
|
|
delete_count += 1;
|
2017-05-17 00:04:56 +08:00
|
|
|
}
|
2018-09-14 04:18:28 +08:00
|
|
|
Debug(3, "Deleted (%d) packets", delete_count );
|
2021-01-07 22:43:53 +08:00
|
|
|
for (
|
|
|
|
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
|
|
|
iterators_it != iterators.end();
|
|
|
|
++iterators_it
|
|
|
|
) {
|
|
|
|
packetqueue_iterator *iterator_it = *iterators_it;
|
|
|
|
*iterator_it = pktQueue.begin();
|
|
|
|
} // end foreach iterator
|
2017-12-08 23:39:24 +08:00
|
|
|
mutex.unlock();
|
2017-05-17 00:04:56 +08:00
|
|
|
}
|
|
|
|
|
2019-11-02 05:29:55 +08:00
|
|
|
// clear queue keeping only specified duration of video -- return number of pkts removed
|
|
|
|
unsigned int zm_packetqueue::clearQueue(struct timeval *duration, int streamId) {
|
|
|
|
|
2020-05-03 06:03:42 +08:00
|
|
|
if ( pktQueue.empty() ) {
|
2019-11-02 05:29:55 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2020-12-16 05:01:18 +08:00
|
|
|
Debug(4, "Locking in clearQueue");
|
2020-12-10 04:01:24 +08:00
|
|
|
mutex.lock();
|
|
|
|
|
2019-11-02 05:29:55 +08:00
|
|
|
struct timeval keep_from;
|
2020-12-10 04:01:24 +08:00
|
|
|
std::list<ZMPacket *>::reverse_iterator it = pktQueue.rbegin();
|
2019-11-02 05:29:55 +08:00
|
|
|
|
2020-05-03 06:03:42 +08:00
|
|
|
struct timeval *t = (*it)->timestamp;
|
|
|
|
timersub(t, duration, &keep_from);
|
2019-11-02 05:29:55 +08:00
|
|
|
++it;
|
|
|
|
|
2020-12-10 04:01:24 +08:00
|
|
|
Debug(3, "Looking for frame before queue keep time with stream id (%d), queue has %d packets",
|
2019-11-02 05:29:55 +08:00
|
|
|
streamId, pktQueue.size());
|
|
|
|
for ( ; it != pktQueue.rend(); ++it) {
|
|
|
|
ZMPacket *zm_packet = *it;
|
|
|
|
AVPacket *av_packet = &(zm_packet->packet);
|
2020-12-10 04:01:24 +08:00
|
|
|
if (
|
|
|
|
(av_packet->stream_index == streamId)
|
|
|
|
and
|
|
|
|
timercmp(zm_packet->timestamp, &keep_from, <=)
|
|
|
|
) {
|
2019-11-02 05:29:55 +08:00
|
|
|
Debug(3, "Found frame before keep time with stream index %d at %d.%d",
|
|
|
|
av_packet->stream_index,
|
2020-05-03 06:03:42 +08:00
|
|
|
zm_packet->timestamp->tv_sec,
|
|
|
|
zm_packet->timestamp->tv_usec);
|
2019-11-02 05:29:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-10 04:01:24 +08:00
|
|
|
if ( it == pktQueue.rend() ) {
|
2019-11-02 05:29:55 +08:00
|
|
|
Debug(1, "Didn't find a frame before queue preserve time. keeping all");
|
2020-12-10 04:01:24 +08:00
|
|
|
mutex.unlock();
|
2019-11-02 05:29:55 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug(3, "Looking for keyframe");
|
|
|
|
for ( ; it != pktQueue.rend(); ++it) {
|
|
|
|
ZMPacket *zm_packet = *it;
|
|
|
|
AVPacket *av_packet = &(zm_packet->packet);
|
2020-12-10 04:01:24 +08:00
|
|
|
if (
|
|
|
|
(av_packet->flags & AV_PKT_FLAG_KEY)
|
|
|
|
and
|
|
|
|
(av_packet->stream_index == streamId)
|
|
|
|
) {
|
2019-11-02 05:29:55 +08:00
|
|
|
Debug(3, "Found keyframe before start with stream index %d at %d.%d",
|
|
|
|
av_packet->stream_index,
|
2020-05-03 06:03:42 +08:00
|
|
|
zm_packet->timestamp->tv_sec,
|
|
|
|
zm_packet->timestamp->tv_usec );
|
2019-11-02 05:29:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( it == pktQueue.rend() ) {
|
|
|
|
Debug(1, "Didn't find a keyframe before event starttime. keeping all" );
|
2020-12-10 04:01:24 +08:00
|
|
|
mutex.unlock();
|
2019-11-02 05:29:55 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int deleted_frames = 0;
|
2020-08-26 07:45:48 +08:00
|
|
|
ZMPacket *zm_packet = nullptr;
|
2020-12-10 04:01:24 +08:00
|
|
|
while ( distance(it, pktQueue.rend()) > 1 ) {
|
2019-11-02 05:29:55 +08:00
|
|
|
zm_packet = pktQueue.front();
|
2021-01-07 22:43:53 +08:00
|
|
|
for (
|
|
|
|
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
|
|
|
iterators_it != iterators.end();
|
|
|
|
++iterators_it
|
|
|
|
) {
|
|
|
|
packetqueue_iterator *iterator_it = *iterators_it;
|
|
|
|
// Have to check each iterator and make sure it doesn't point to the packet we are about to delete
|
|
|
|
if ( *(*iterator_it) == zm_packet ) {
|
|
|
|
Debug(4, "Bumping it because it is at the front that we are deleting");
|
|
|
|
++(*iterators_it);
|
|
|
|
}
|
|
|
|
} // end foreach iterator
|
2019-11-02 05:29:55 +08:00
|
|
|
pktQueue.pop_front();
|
|
|
|
packet_counts[zm_packet->packet.stream_index] -= 1;
|
2021-01-07 22:43:53 +08:00
|
|
|
//if ( zm_packet->image_index == -1 )
|
2020-12-16 05:01:18 +08:00
|
|
|
delete zm_packet;
|
2019-11-02 05:29:55 +08:00
|
|
|
deleted_frames += 1;
|
|
|
|
}
|
2020-08-26 07:45:48 +08:00
|
|
|
zm_packet = nullptr;
|
2019-11-02 05:29:55 +08:00
|
|
|
Debug(3, "Deleted %d frames", deleted_frames);
|
2020-12-10 04:01:24 +08:00
|
|
|
mutex.unlock();
|
2019-11-02 05:29:55 +08:00
|
|
|
|
|
|
|
return deleted_frames;
|
|
|
|
}
|
|
|
|
|
2017-05-17 00:04:56 +08:00
|
|
|
unsigned int zm_packetqueue::size() {
|
|
|
|
return pktQueue.size();
|
|
|
|
}
|
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
int zm_packetqueue::packet_count(int stream_id) {
|
2018-10-15 22:51:56 +08:00
|
|
|
return packet_counts[stream_id];
|
2021-01-07 22:43:53 +08:00
|
|
|
} // end int zm_packetqueue::packet_count(int stream_id)
|
2017-05-17 00:04:56 +08:00
|
|
|
|
2020-12-22 23:20:44 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
// Returns a packet. Packet will be locked
|
|
|
|
ZMPacket *zm_packetqueue::get_packet(packetqueue_iterator *it) {
|
2021-01-27 01:23:44 +08:00
|
|
|
if ( deleting or zm_terminate )
|
|
|
|
return nullptr;
|
2017-12-01 03:37:36 +08:00
|
|
|
|
2021-01-19 22:46:08 +08:00
|
|
|
Debug(4, "Locking in get_packet using it %p queue end? %d, packet %p",
|
|
|
|
*it, (*it == pktQueue.end()), *(*it));
|
2020-12-10 04:01:24 +08:00
|
|
|
std::unique_lock<std::mutex> lck(mutex);
|
2021-01-07 22:43:53 +08:00
|
|
|
Debug(4, "Have Lock in get_packet");
|
2020-12-10 04:01:24 +08:00
|
|
|
|
2021-01-14 23:31:29 +08:00
|
|
|
while ( (!pktQueue.size()) or (*it == pktQueue.end()) ) {
|
2021-01-07 22:43:53 +08:00
|
|
|
if ( deleting or zm_terminate )
|
|
|
|
return nullptr;
|
2021-01-14 23:31:29 +08:00
|
|
|
Debug(2, "waiting. Queue size %d it == end? %d", pktQueue.size(), (*it == pktQueue.end()));
|
2020-12-10 04:01:24 +08:00
|
|
|
condition.wait(lck);
|
2019-02-25 23:21:43 +08:00
|
|
|
}
|
2021-01-07 22:43:53 +08:00
|
|
|
if ( deleting or zm_terminate )
|
2020-12-15 23:14:19 +08:00
|
|
|
return nullptr;
|
2017-12-01 03:37:36 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
ZMPacket *p = *(*it);
|
|
|
|
if ( !p ) {
|
|
|
|
Error("Null p?!");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-01-19 22:46:08 +08:00
|
|
|
Debug(3, "get_packet %p image_index: %d, about to lock packet", p, p->image_index);
|
2021-01-07 22:43:53 +08:00
|
|
|
while ( !(zm_terminate or deleting) and !p->trylock() ) {
|
|
|
|
Debug(3, "waiting. Queue size %d it == end? %d", pktQueue.size(), ( *it == pktQueue.end() ) );
|
2020-12-10 04:01:24 +08:00
|
|
|
condition.wait(lck);
|
|
|
|
}
|
2020-09-26 04:20:19 +08:00
|
|
|
Debug(2, "Locked packet, unlocking packetqueue mutex");
|
2019-02-25 23:21:43 +08:00
|
|
|
return p;
|
2021-01-07 22:43:53 +08:00
|
|
|
} // end ZMPacket *zm_packetqueue::get_packet(it)
|
|
|
|
|
|
|
|
bool zm_packetqueue::increment_it(packetqueue_iterator *it) {
|
2021-01-19 22:46:08 +08:00
|
|
|
Debug(2, "Incrementing %p, queue size %d, end? %d", it, pktQueue.size(), ((*it) == pktQueue.end()));
|
|
|
|
if ( (*it) == pktQueue.end() ) {
|
2021-01-07 22:43:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
++(*it);
|
|
|
|
if ( *it != pktQueue.end() ) {
|
2021-01-19 22:46:08 +08:00
|
|
|
Debug(2, "Incrementing %p, %p still not at end %p, so returning true", it, *it, pktQueue.end());
|
2021-01-07 22:43:53 +08:00
|
|
|
return true;
|
2020-12-10 04:01:24 +08:00
|
|
|
}
|
2021-01-07 22:43:53 +08:00
|
|
|
return false;
|
|
|
|
} // end bool zm_packetqueue::increment_it(packetqueue_iterator *it)
|
2020-12-10 04:01:24 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
// Increment it only considering packets for a given stream
|
|
|
|
bool zm_packetqueue::increment_it(packetqueue_iterator *it, int stream_id) {
|
|
|
|
Debug(2, "Incrementing %p, queue size %d, end? %d", it, pktQueue.size(), (*it == pktQueue.end()));
|
|
|
|
if ( *it == pktQueue.end() ) {
|
2017-12-01 03:37:36 +08:00
|
|
|
return false;
|
|
|
|
}
|
2019-06-21 03:14:20 +08:00
|
|
|
|
2021-01-07 22:43:53 +08:00
|
|
|
do {
|
|
|
|
++(*it);
|
|
|
|
} while ( (*it != pktQueue.end()) and ( (*(*it))->packet.stream_index != stream_id) );
|
|
|
|
|
|
|
|
if ( *it != pktQueue.end() ) {
|
|
|
|
Debug(2, "Incrementing %p, still not at end, so incrementing", it);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} // end bool zm_packetqueue::increment_it(packetqueue_iterator *it)
|
2020-12-22 23:20:44 +08:00
|
|
|
|
|
|
|
std::list<ZMPacket *>::iterator zm_packetqueue::get_event_start_packet_it(
|
|
|
|
std::list<ZMPacket *>::iterator snapshot_it,
|
|
|
|
unsigned int pre_event_count
|
|
|
|
) {
|
|
|
|
|
|
|
|
std::list<ZMPacket *>::iterator it = snapshot_it;
|
2021-01-27 01:23:44 +08:00
|
|
|
dumpPacket(&((*it)->packet));
|
2020-12-22 23:20:44 +08:00
|
|
|
// Step one count back pre_event_count frames as the minimum
|
|
|
|
// Do not assume that snapshot_it is video
|
|
|
|
// snapshot it might already point to the beginning
|
|
|
|
while ( ( it != pktQueue.begin() ) and pre_event_count ) {
|
2021-01-27 01:23:44 +08:00
|
|
|
Debug(1, "Previous packet pre_event_count %d stream_index %d keyframe %d", pre_event_count, (*it)->packet.stream_index, (*it)->keyframe);
|
|
|
|
dumpPacket(&((*it)->packet));
|
|
|
|
if ( (*it)->packet.stream_index == video_stream_id ) {
|
2020-12-22 23:20:44 +08:00
|
|
|
pre_event_count --;
|
2021-01-27 01:23:44 +08:00
|
|
|
if ( ! pre_event_count )
|
|
|
|
break;
|
2020-12-22 23:20:44 +08:00
|
|
|
}
|
|
|
|
it--;
|
|
|
|
}
|
2021-01-27 01:23:44 +08:00
|
|
|
// it either points to beginning or we have seen pre_event_count video packets.
|
|
|
|
|
2020-12-22 23:20:44 +08:00
|
|
|
if ( it == pktQueue.begin() ) {
|
|
|
|
Debug(1, "Hit begin");
|
|
|
|
// hit end, the first packet in the queue should ALWAYS be a video keyframe.
|
|
|
|
// So we should be able to return it.
|
2021-01-07 22:43:53 +08:00
|
|
|
if ( pre_event_count ) {
|
2021-01-13 03:13:12 +08:00
|
|
|
if ( (*it)->image_index < (int)pre_event_count ) {
|
2021-01-12 06:18:14 +08:00
|
|
|
// probably just starting up
|
|
|
|
Debug(1, "Hit end of packetqueue before satisfying pre_event_count. Needed %d more video frames", pre_event_count);
|
|
|
|
} else {
|
|
|
|
Warning("Hit end of packetqueue before satisfying pre_event_count. Needed %d more video frames", pre_event_count);
|
|
|
|
}
|
|
|
|
dumpPacket(&((*it)->packet));
|
2021-01-07 22:43:53 +08:00
|
|
|
}
|
2020-12-22 23:20:44 +08:00
|
|
|
return it;
|
|
|
|
}
|
2021-01-27 01:23:44 +08:00
|
|
|
|
|
|
|
// Not at beginning, so must be pointing at a video keyframe or maybe pre_event_count == 0
|
2020-12-22 23:20:44 +08:00
|
|
|
if ( (*it)->keyframe ) {
|
2021-01-27 01:23:44 +08:00
|
|
|
dumpPacket(&((*it)->packet), "Found video keyframe, Returning");
|
2020-12-22 23:20:44 +08:00
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
2021-01-27 01:23:44 +08:00
|
|
|
while ( it-- != pktQueue.begin() ) {
|
|
|
|
dumpPacket(&((*it)->packet), "No keyframe");
|
|
|
|
if ( (*it)->packet.stream_index == video_stream_id and (*it)->keyframe )
|
|
|
|
return it; // Success
|
2020-12-22 23:20:44 +08:00
|
|
|
}
|
|
|
|
if ( !(*it)->keyframe ) {
|
2021-01-27 01:23:44 +08:00
|
|
|
Warning("Hit end of packetqueue before satisfying pre_event_count. Needed %d more video frames", pre_event_count);
|
2020-12-22 23:20:44 +08:00
|
|
|
}
|
|
|
|
return it;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
std::list<ZMPacket *>::iterator it = snapshot_it.base();
|
|
|
|
// Step one count back pre_event_count frames as the minimum
|
|
|
|
// Do not assume that snapshot_it is video
|
|
|
|
while ( ( it++ != pktQueue.rend() ) and pre_event_count ) {
|
|
|
|
// Is video, maybe should compare stream_id instead
|
|
|
|
if ( *it->image_index != -1 ) {
|
|
|
|
pre_event_count --;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( it == pktQueue.rend() ) {
|
|
|
|
// hit end, the first packet in the queue should ALWAYS be a video keyframe.
|
|
|
|
// So we should be able to return it.
|
|
|
|
if ( pre_event_count )
|
|
|
|
Warning("Hit end of packetqueue before satisfying pre_event_count. Needed %d more video frames", pre_event_count);
|
|
|
|
return it.base();
|
|
|
|
}
|
|
|
|
if ( *it->keyframe ) {
|
|
|
|
return (it++).base();
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( ( it++ != pktQueue.rend() ) and ! (*it)->keyframe ) { }
|
|
|
|
if ( it == pktQueue.rend() ) {
|
|
|
|
// hit end, the first packet in the queue should ALWAYS be a video keyframe.
|
|
|
|
// So we should be able to return it.
|
|
|
|
if ( pre_event_count )
|
|
|
|
Warning("Hit end of packetqueue before satisfying pre_event_count. Needed %d more video frames", pre_event_count);
|
|
|
|
return it.base();
|
|
|
|
}
|
|
|
|
return (it++).base();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-06-21 03:14:20 +08:00
|
|
|
void zm_packetqueue::dumpQueue() {
|
|
|
|
std::list<ZMPacket *>::reverse_iterator it;
|
|
|
|
for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) {
|
|
|
|
ZMPacket *zm_packet = *it;
|
|
|
|
AVPacket *av_packet = &(zm_packet->packet);
|
|
|
|
dumpPacket(av_packet);
|
|
|
|
}
|
|
|
|
}
|
2021-01-07 22:43:53 +08:00
|
|
|
|
|
|
|
/* Returns an iterator to the first video keyframe in the queue.
|
|
|
|
* nullptr if no keyframe video packet exists.
|
|
|
|
*/
|
|
|
|
packetqueue_iterator * zm_packetqueue::get_video_it(bool wait) {
|
|
|
|
packetqueue_iterator *it = new packetqueue_iterator;
|
|
|
|
iterators.push_back(it);
|
|
|
|
|
|
|
|
std::unique_lock<std::mutex> lck(mutex);
|
|
|
|
*it = pktQueue.begin();
|
|
|
|
|
|
|
|
if ( wait ) {
|
|
|
|
while ( ((! pktQueue.size()) or (*it == pktQueue.end())) and !zm_terminate and !deleting ) {
|
|
|
|
Debug(2, "waiting. Queue size %d it == end? %d", pktQueue.size(), ( *it == pktQueue.end() ) );
|
|
|
|
condition.wait(lck);
|
|
|
|
*it = pktQueue.begin();
|
|
|
|
}
|
|
|
|
if ( deleting or zm_terminate ) {
|
|
|
|
delete it;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( *it != pktQueue.end() ) {
|
|
|
|
ZMPacket *zm_packet = *(*it);
|
|
|
|
if ( !zm_packet ) {
|
|
|
|
Error("Null zmpacket in queue!?");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Debug(1, "Packet keyframe %d for stream %d, so returning the it to it",
|
|
|
|
zm_packet->keyframe, zm_packet->packet.stream_index);
|
|
|
|
if ( zm_packet->keyframe and ( zm_packet->packet.stream_index == video_stream_id ) ) {
|
|
|
|
Debug(1, "Found a keyframe for stream %d, so returning the it to it", video_stream_id);
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
++(*it);
|
|
|
|
}
|
|
|
|
Debug(1, "DIdn't Found a keyframe for stream %d, so returning the it to it", video_stream_id);
|
|
|
|
return it;
|
|
|
|
}
|