Switch ZMPacket * to a shared_ptr<ZMPacket>. This is so that in LockedPacket we can unlock and then notify and be confident that packet_ won't have been deleted. Change ZMPacket->timestamp to be a timeval instead of timeval *. This might not have been necessary but I like it. No longer cuse the ZMPacket object to wrap the shared image buffers and timestamps. Use a vector for image_buffers.
This commit is contained in:
parent
9ee24170a9
commit
2cf6ad8089
|
@ -1 +1 @@
|
||||||
Subproject commit cd7fd49becad6010a1b8466bfebbd93999a39878
|
Subproject commit d714323e693ba106be6af363295d950f50ca15e0
|
|
@ -24,6 +24,8 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class Monitor;
|
class Monitor;
|
||||||
class ZMPacket;
|
class ZMPacket;
|
||||||
|
|
||||||
|
@ -133,7 +135,7 @@ public:
|
||||||
|
|
||||||
virtual int PrimeCapture() { return 0; }
|
virtual int PrimeCapture() { return 0; }
|
||||||
virtual int PreCapture() = 0;
|
virtual int PreCapture() = 0;
|
||||||
virtual int Capture(ZMPacket &p) = 0;
|
virtual int Capture(std::shared_ptr<ZMPacket> &p) = 0;
|
||||||
virtual int PostCapture() = 0;
|
virtual int PostCapture() = 0;
|
||||||
virtual int Close() = 0;
|
virtual int Close() = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -285,7 +285,7 @@ void Event::createNotes(std::string ¬es) {
|
||||||
|
|
||||||
bool Event::WriteFrameImage(
|
bool Event::WriteFrameImage(
|
||||||
Image *image,
|
Image *image,
|
||||||
struct timeval timestamp,
|
timeval timestamp,
|
||||||
const char *event_file,
|
const char *event_file,
|
||||||
bool alarm_frame) const {
|
bool alarm_frame) const {
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ bool Event::WriteFrameImage(
|
||||||
// stash the image we plan to use in another pointer regardless if timestamped.
|
// stash the image we plan to use in another pointer regardless if timestamped.
|
||||||
// exif is only timestamp at present this switches on or off for write
|
// exif is only timestamp at present this switches on or off for write
|
||||||
Image *ts_image = new Image(*image);
|
Image *ts_image = new Image(*image);
|
||||||
monitor->TimestampImage(ts_image, ×tamp);
|
monitor->TimestampImage(ts_image, timestamp);
|
||||||
rc = ts_image->WriteJpeg(event_file, thisquality,
|
rc = ts_image->WriteJpeg(event_file, thisquality,
|
||||||
(monitor->Exif() ? timestamp : (timeval){0,0}));
|
(monitor->Exif() ? timestamp : (timeval){0,0}));
|
||||||
delete(ts_image);
|
delete(ts_image);
|
||||||
|
@ -311,9 +311,8 @@ bool Event::WriteFrameImage(
|
||||||
return rc;
|
return rc;
|
||||||
} // end Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame )
|
} // end Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame )
|
||||||
|
|
||||||
bool Event::WritePacket(ZMPacket &packet) {
|
bool Event::WritePacket(const std::shared_ptr<ZMPacket>&packet) {
|
||||||
|
if (videoStore->writePacket(packet) < 0)
|
||||||
if ( videoStore->writePacket(&packet) < 0 )
|
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
} // bool Event::WriteFrameVideo
|
} // bool Event::WriteFrameVideo
|
||||||
|
@ -420,7 +419,7 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) {
|
||||||
} // end if update
|
} // end if update
|
||||||
} // void Event::updateNotes(const StringSetMap &newNoteSetMap)
|
} // void Event::updateNotes(const StringSetMap &newNoteSetMap)
|
||||||
|
|
||||||
void Event::AddPacket(ZMPacket *packet) {
|
void Event::AddPacket(const std::shared_ptr<ZMPacket>&packet) {
|
||||||
|
|
||||||
have_video_keyframe = have_video_keyframe ||
|
have_video_keyframe = have_video_keyframe ||
|
||||||
( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) &&
|
( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) &&
|
||||||
|
@ -437,8 +436,8 @@ void Event::AddPacket(ZMPacket *packet) {
|
||||||
//FIXME if it fails, we should write a jpeg
|
//FIXME if it fails, we should write a jpeg
|
||||||
}
|
}
|
||||||
if ((packet->codec_type == AVMEDIA_TYPE_VIDEO) or packet->image)
|
if ((packet->codec_type == AVMEDIA_TYPE_VIDEO) or packet->image)
|
||||||
AddFrame(packet->image, *(packet->timestamp), packet->zone_stats, packet->score, packet->analysis_image);
|
AddFrame(packet->image, packet->timestamp, packet->zone_stats, packet->score, packet->analysis_image);
|
||||||
end_time = *packet->timestamp;
|
end_time = packet->timestamp;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,8 +111,8 @@ class Event {
|
||||||
const struct timeval &StartTime() const { return start_time; }
|
const struct timeval &StartTime() const { return start_time; }
|
||||||
const struct timeval &EndTime() const { return end_time; }
|
const struct timeval &EndTime() const { return end_time; }
|
||||||
|
|
||||||
void AddPacket(ZMPacket *p);
|
void AddPacket(const std::shared_ptr<ZMPacket> &p);
|
||||||
bool WritePacket(ZMPacket &p);
|
bool WritePacket(const std::shared_ptr<ZMPacket> &p);
|
||||||
bool SendFrameImage(const Image *image, bool alarm_frame=false);
|
bool SendFrameImage(const Image *image, bool alarm_frame=false);
|
||||||
bool WriteFrameImage(
|
bool WriteFrameImage(
|
||||||
Image *image,
|
Image *image,
|
||||||
|
|
|
@ -189,7 +189,7 @@ int FfmpegCamera::PreCapture() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FfmpegCamera::Capture(ZMPacket &zm_packet) {
|
int FfmpegCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
if (!mCanCapture) return -1;
|
if (!mCanCapture) return -1;
|
||||||
|
|
||||||
start_read_time = time(nullptr);
|
start_read_time = time(nullptr);
|
||||||
|
@ -236,14 +236,14 @@ int FfmpegCamera::Capture(ZMPacket &zm_packet) {
|
||||||
ZM_DUMP_STREAM_PACKET(stream, packet, "ffmpeg_camera in");
|
ZM_DUMP_STREAM_PACKET(stream, packet, "ffmpeg_camera in");
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
zm_packet.codec_type = stream->codecpar->codec_type;
|
zm_packet->codec_type = stream->codecpar->codec_type;
|
||||||
#else
|
#else
|
||||||
zm_packet.codec_type = stream->codec->codec_type;
|
zm_packet->codec_type = stream->codec->codec_type;
|
||||||
#endif
|
#endif
|
||||||
bytes += packet.size;
|
bytes += packet.size;
|
||||||
zm_packet.set_packet(&packet);
|
zm_packet->set_packet(&packet);
|
||||||
zm_packet.stream = stream;
|
zm_packet->stream = stream;
|
||||||
zm_packet.pts = av_rescale_q(packet.pts, stream->time_base, AV_TIME_BASE_Q);
|
zm_packet->pts = av_rescale_q(packet.pts, stream->time_base, AV_TIME_BASE_Q);
|
||||||
if ( packet.pts != AV_NOPTS_VALUE ) {
|
if ( packet.pts != AV_NOPTS_VALUE ) {
|
||||||
if ( stream == mVideoStream ) {
|
if ( stream == mVideoStream ) {
|
||||||
if (mFirstVideoPTS == AV_NOPTS_VALUE)
|
if (mFirstVideoPTS == AV_NOPTS_VALUE)
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#include "zm_camera.h"
|
#include "zm_camera.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||||
typedef struct DecodeContext {
|
typedef struct DecodeContext {
|
||||||
AVBufferRef *hw_device_ref;
|
AVBufferRef *hw_device_ref;
|
||||||
|
@ -93,7 +95,7 @@ class FfmpegCamera : public Camera {
|
||||||
|
|
||||||
int PrimeCapture() override;
|
int PrimeCapture() override;
|
||||||
int PreCapture() override;
|
int PreCapture() override;
|
||||||
int Capture(ZMPacket &p) override;
|
int Capture(std::shared_ptr<ZMPacket> &p) override;
|
||||||
int PostCapture() override;
|
int PostCapture() override;
|
||||||
private:
|
private:
|
||||||
static int FfmpegInterruptCallback(void*ctx);
|
static int FfmpegInterruptCallback(void*ctx);
|
||||||
|
|
|
@ -87,8 +87,8 @@ int FileCamera::PreCapture() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileCamera::Capture( ZMPacket &zm_packet ) {
|
int FileCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
return zm_packet.image->ReadJpeg(path, colours, subpixelorder) ? 1 : -1;
|
return zm_packet->image->ReadJpeg(path, colours, subpixelorder) ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileCamera::PostCapture() {
|
int FileCamera::PostCapture() {
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
void Initialise();
|
void Initialise();
|
||||||
void Terminate();
|
void Terminate();
|
||||||
int PreCapture() override;
|
int PreCapture() override;
|
||||||
int Capture(ZMPacket &p) override;
|
int Capture(std::shared_ptr<ZMPacket> &p) override;
|
||||||
int PostCapture() override;
|
int PostCapture() override;
|
||||||
int Close() override { return 0; };
|
int Close() override { return 0; };
|
||||||
};
|
};
|
||||||
|
|
|
@ -2036,16 +2036,16 @@ int LocalCamera::PreCapture() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LocalCamera::Capture(ZMPacket &zm_packet) {
|
int LocalCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
// We assume that the avpacket is allocated, and just needs to be filled
|
// We assume that the avpacket is allocated, and just needs to be filled
|
||||||
static uint8_t* buffer = nullptr;
|
static uint8_t* buffer = nullptr;
|
||||||
int buffer_bytesused = 0;
|
int buffer_bytesused = 0;
|
||||||
int capture_frame = -1;
|
int capture_frame = -1;
|
||||||
|
|
||||||
int captures_per_frame = 1;
|
int captures_per_frame = 1;
|
||||||
if ( channel_count > 1 )
|
if (channel_count > 1)
|
||||||
captures_per_frame = v4l_captures_per_frame;
|
captures_per_frame = v4l_captures_per_frame;
|
||||||
if ( captures_per_frame <= 0 ) {
|
if (captures_per_frame <= 0) {
|
||||||
captures_per_frame = 1;
|
captures_per_frame = 1;
|
||||||
Warning("Invalid Captures Per Frame setting: %d", captures_per_frame);
|
Warning("Invalid Captures Per Frame setting: %d", captures_per_frame);
|
||||||
}
|
}
|
||||||
|
@ -2191,22 +2191,22 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
|
||||||
|
|
||||||
} /* prime capture */
|
} /* prime capture */
|
||||||
|
|
||||||
if (!zm_packet.image) {
|
if (!zm_packet->image) {
|
||||||
Debug(4, "Allocating image");
|
Debug(4, "Allocating image");
|
||||||
zm_packet.image = new Image(width, height, colours, subpixelorder);
|
zm_packet->image = new Image(width, height, colours, subpixelorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( conversion_type != 0 ) {
|
if (conversion_type != 0) {
|
||||||
Debug(3, "Performing format conversion %d", conversion_type);
|
Debug(3, "Performing format conversion %d", conversion_type);
|
||||||
|
|
||||||
/* Request a writeable buffer of the target image */
|
/* Request a writeable buffer of the target image */
|
||||||
uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder);
|
uint8_t *directbuffer = zm_packet->image->WriteBuffer(width, height, colours, subpixelorder);
|
||||||
if ( directbuffer == nullptr ) {
|
if (directbuffer == nullptr) {
|
||||||
Error("Failed requesting writeable buffer for the captured image.");
|
Error("Failed requesting writeable buffer for the captured image.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
if ( conversion_type == 1 ) {
|
if (conversion_type == 1) {
|
||||||
Debug(9, "Calling sws_scale to perform the conversion");
|
Debug(9, "Calling sws_scale to perform the conversion");
|
||||||
/* Use swscale to convert the image directly into the shared memory */
|
/* Use swscale to convert the image directly into the shared memory */
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
@ -2236,20 +2236,20 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
|
||||||
// Need to store the jpeg data too
|
// Need to store the jpeg data too
|
||||||
Debug(9, "Decoding the JPEG image");
|
Debug(9, "Decoding the JPEG image");
|
||||||
/* JPEG decoding */
|
/* JPEG decoding */
|
||||||
zm_packet.image->DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder);
|
zm_packet->image->DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Debug(3, "No format conversion performed. Assigning the image");
|
Debug(3, "No format conversion performed. Assigning the image");
|
||||||
|
|
||||||
/* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */
|
/* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */
|
||||||
zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
zm_packet->image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
||||||
} // end if doing conversion or not
|
} // end if doing conversion or not
|
||||||
|
|
||||||
zm_packet.packet.stream_index = mVideoStreamId;
|
zm_packet->packet.stream_index = mVideoStreamId;
|
||||||
zm_packet.stream = mVideoStream;
|
zm_packet->stream = mVideoStream;
|
||||||
zm_packet.codec_type = AVMEDIA_TYPE_VIDEO;
|
zm_packet->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||||
zm_packet.keyframe = 1;
|
zm_packet->keyframe = 1;
|
||||||
return 1;
|
return 1;
|
||||||
} // end int LocalCamera::Capture()
|
} // end int LocalCamera::Capture()
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ public:
|
||||||
|
|
||||||
int PrimeCapture() override;
|
int PrimeCapture() override;
|
||||||
int PreCapture() override;
|
int PreCapture() override;
|
||||||
int Capture(ZMPacket &p) override;
|
int Capture(std::shared_ptr<ZMPacket> &p) override;
|
||||||
int PostCapture() override;
|
int PostCapture() override;
|
||||||
int Close() override { return 0; };
|
int Close() override { return 0; };
|
||||||
|
|
||||||
|
|
|
@ -996,12 +996,10 @@ bool Monitor::connect() {
|
||||||
if (!camera) LoadCamera();
|
if (!camera) LoadCamera();
|
||||||
|
|
||||||
Debug(3, "Allocating %d image buffers", image_buffer_count);
|
Debug(3, "Allocating %d image buffers", image_buffer_count);
|
||||||
image_buffer = new ZMPacket[image_buffer_count];
|
image_buffer.reserve(image_buffer_count);
|
||||||
for (int32_t i = 0; i < image_buffer_count; i++) {
|
for (int32_t i = 0; i < image_buffer_count; i++) {
|
||||||
image_buffer[i].image_index = i;
|
image_buffer[i] = new Image(width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]));
|
||||||
image_buffer[i].timestamp = &(shared_timestamps[i]);
|
image_buffer[i]->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */
|
||||||
image_buffer[i].image = new Image(width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]));
|
|
||||||
image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (purpose == CAPTURE) {
|
if (purpose == CAPTURE) {
|
||||||
|
@ -1096,16 +1094,10 @@ bool Monitor::disconnect() {
|
||||||
}
|
}
|
||||||
#endif // ZM_MEM_MAPPED
|
#endif // ZM_MEM_MAPPED
|
||||||
|
|
||||||
if (image_buffer) {
|
|
||||||
for ( int32_t i = 0; i < image_buffer_count; i++ ) {
|
for ( int32_t i = 0; i < image_buffer_count; i++ ) {
|
||||||
// We delete the image because it is an object pointing to space that won't be free'd.
|
// We delete the image because it is an object pointing to space that won't be free'd.
|
||||||
delete image_buffer[i].image;
|
delete image_buffer[i];
|
||||||
image_buffer[i].image = nullptr;
|
image_buffer[i] = nullptr;
|
||||||
// We don't delete the timestamp because it is just a pointer to shared mem.
|
|
||||||
image_buffer[i].timestamp = nullptr;
|
|
||||||
}
|
|
||||||
delete[] image_buffer;
|
|
||||||
image_buffer = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1177,19 +1169,18 @@ int Monitor::GetImage(int32_t index, int scale) {
|
||||||
Image *image;
|
Image *image;
|
||||||
// If we are going to be modifying the snapshot before writing, then we need to copy it
|
// If we are going to be modifying the snapshot before writing, then we need to copy it
|
||||||
if ( ( scale != ZM_SCALE_BASE ) || ( !config.timestamp_on_capture ) ) {
|
if ( ( scale != ZM_SCALE_BASE ) || ( !config.timestamp_on_capture ) ) {
|
||||||
ZMPacket *snap = &image_buffer[index];
|
alarm_image.Assign(*image_buffer[index]);
|
||||||
alarm_image.Assign(*snap->image);
|
|
||||||
|
|
||||||
if ( scale != ZM_SCALE_BASE ) {
|
if (scale != ZM_SCALE_BASE) {
|
||||||
alarm_image.Scale(scale);
|
alarm_image.Scale(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config.timestamp_on_capture ) {
|
if ( !config.timestamp_on_capture ) {
|
||||||
TimestampImage(&alarm_image, snap->timestamp);
|
TimestampImage(&alarm_image, shared_timestamps[index]);
|
||||||
}
|
}
|
||||||
image = &alarm_image;
|
image = &alarm_image;
|
||||||
} else {
|
} else {
|
||||||
image = image_buffer[index].image;
|
image = image_buffer[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char filename[PATH_MAX];
|
static char filename[PATH_MAX];
|
||||||
|
@ -1206,15 +1197,15 @@ ZMPacket *Monitor::getSnapshot(int index) const {
|
||||||
if ( (index < 0) || (index > image_buffer_count) ) {
|
if ( (index < 0) || (index > image_buffer_count) ) {
|
||||||
index = shared_data->last_write_index;
|
index = shared_data->last_write_index;
|
||||||
}
|
}
|
||||||
return &image_buffer[index];
|
return new ZMPacket(image_buffer[index], shared_timestamps[index]);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval Monitor::GetTimestamp(int index) const {
|
struct timeval Monitor::GetTimestamp(int index) const {
|
||||||
ZMPacket *packet = getSnapshot(index);
|
ZMPacket *packet = getSnapshot(index);
|
||||||
if ( packet )
|
if (packet)
|
||||||
return *packet->timestamp;
|
return packet->timestamp;
|
||||||
|
|
||||||
static struct timeval null_tv = { 0, 0 };
|
static struct timeval null_tv = { 0, 0 };
|
||||||
return null_tv;
|
return null_tv;
|
||||||
|
@ -1235,58 +1226,6 @@ uint64_t Monitor::GetLastEventId() const {
|
||||||
// This function is crap.
|
// This function is crap.
|
||||||
double Monitor::GetFPS() const {
|
double Monitor::GetFPS() const {
|
||||||
return get_capture_fps();
|
return get_capture_fps();
|
||||||
// last_write_index is the last capture index. It starts as == image_buffer_count so that the first asignment % image_buffer_count = 0;
|
|
||||||
int32_t index1 = shared_data->last_write_index;
|
|
||||||
if ( index1 >= image_buffer_count ) {
|
|
||||||
// last_write_index only has this value on startup before capturing anything.
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
Debug(2, "index1(%d)", index1);
|
|
||||||
ZMPacket *snap1 = &image_buffer[index1];
|
|
||||||
if ( !snap1->timestamp->tv_sec ) {
|
|
||||||
// This should be impossible
|
|
||||||
Warning("Impossible situation. No timestamp on captured image index was %d, image-buffer_count was (%d)", index1, image_buffer_count);
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
struct timeval time1 = *snap1->timestamp;
|
|
||||||
|
|
||||||
int32_t fps_image_count = image_buffer_count;
|
|
||||||
|
|
||||||
int32_t index2 = (index1+1)%image_buffer_count;
|
|
||||||
Debug(2, "index2(%d)", index2);
|
|
||||||
ZMPacket *snap2 = &image_buffer[index2];
|
|
||||||
// the timestamp pointers are initialized on connection, so that's redundant
|
|
||||||
// tv_sec is probably only zero during the first loop of capturing, so this basically just counts the unused images.
|
|
||||||
// The problem is that there is no locking, and we set the timestamp before we set last_write_index,
|
|
||||||
// so there is a small window where the next image can have a timestamp in the future
|
|
||||||
while ( !snap2->timestamp->tv_sec || tvDiffSec(*snap2->timestamp, *snap1->timestamp) < 0 ) {
|
|
||||||
if ( index1 == index2 ) {
|
|
||||||
// All images are uncaptured
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
index2 = (index2+1)%image_buffer_count;
|
|
||||||
snap2 = &image_buffer[ index2 ];
|
|
||||||
fps_image_count--;
|
|
||||||
}
|
|
||||||
struct timeval time2 = *snap2->timestamp;
|
|
||||||
|
|
||||||
double time_diff = tvDiffSec( time2, time1 );
|
|
||||||
if ( ! time_diff ) {
|
|
||||||
Error("No diff between time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d",
|
|
||||||
time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count);
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
double curr_fps = fps_image_count/time_diff;
|
|
||||||
|
|
||||||
if ( curr_fps < 0.0 ) {
|
|
||||||
Error("Negative FPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d",
|
|
||||||
curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count);
|
|
||||||
return 0.0;
|
|
||||||
} else {
|
|
||||||
Debug(2, "GetFPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d",
|
|
||||||
curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count);
|
|
||||||
}
|
|
||||||
return curr_fps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* I think this returns the # of micro seconds that we should sleep in order to maintain the desired analysis rate */
|
/* I think this returns the # of micro seconds that we should sleep in order to maintain the desired analysis rate */
|
||||||
|
@ -1772,7 +1711,7 @@ bool Monitor::Analyse() {
|
||||||
// get_analysis_packet will lock the packet and may wait if analysis_it is at the end
|
// get_analysis_packet will lock the packet and may wait if analysis_it is at the end
|
||||||
ZMLockedPacket *packet_lock = packetqueue.get_packet(analysis_it);
|
ZMLockedPacket *packet_lock = packetqueue.get_packet(analysis_it);
|
||||||
if (!packet_lock) return false;
|
if (!packet_lock) return false;
|
||||||
ZMPacket *snap = packet_lock->packet_;
|
std::shared_ptr<ZMPacket> snap = packet_lock->packet_;
|
||||||
|
|
||||||
// Is it possible for snap->score to be ! -1 ? Not if everything is working correctly
|
// Is it possible for snap->score to be ! -1 ? Not if everything is working correctly
|
||||||
if (snap->score != -1) {
|
if (snap->score != -1) {
|
||||||
|
@ -1908,7 +1847,7 @@ bool Monitor::Analyse() {
|
||||||
}
|
}
|
||||||
} // end if decoding enabled
|
} // end if decoding enabled
|
||||||
|
|
||||||
struct timeval *timestamp = snap->timestamp;
|
struct timeval *timestamp = &snap->timestamp;
|
||||||
|
|
||||||
if (Active() and (function == MODECT or function == MOCORD)) {
|
if (Active() and (function == MODECT or function == MOCORD)) {
|
||||||
Debug(3, "signal and active and modect");
|
Debug(3, "signal and active and modect");
|
||||||
|
@ -2004,7 +1943,7 @@ bool Monitor::Analyse() {
|
||||||
// This gets a lock on the starting packet
|
// This gets a lock on the starting packet
|
||||||
|
|
||||||
ZMLockedPacket *starting_packet_lock = nullptr;
|
ZMLockedPacket *starting_packet_lock = nullptr;
|
||||||
ZMPacket *starting_packet = nullptr;
|
std::shared_ptr<ZMPacket> starting_packet = nullptr;
|
||||||
if (*start_it != snap_it) {
|
if (*start_it != snap_it) {
|
||||||
starting_packet_lock = packetqueue.get_packet(start_it);
|
starting_packet_lock = packetqueue.get_packet(start_it);
|
||||||
if (!starting_packet_lock) {
|
if (!starting_packet_lock) {
|
||||||
|
@ -2017,7 +1956,7 @@ bool Monitor::Analyse() {
|
||||||
starting_packet = snap;
|
starting_packet = snap;
|
||||||
}
|
}
|
||||||
|
|
||||||
event = new Event(this, *(starting_packet->timestamp), "Continuous", noteSetMap);
|
event = new Event(this, starting_packet->timestamp, "Continuous", noteSetMap);
|
||||||
// Write out starting packets, do not modify packetqueue it will garbage collect itself
|
// Write out starting packets, do not modify packetqueue it will garbage collect itself
|
||||||
while (starting_packet and ((*start_it) != snap_it)) {
|
while (starting_packet and ((*start_it) != snap_it)) {
|
||||||
event->AddPacket(starting_packet);
|
event->AddPacket(starting_packet);
|
||||||
|
@ -2106,7 +2045,7 @@ bool Monitor::Analyse() {
|
||||||
(pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count)
|
(pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count)
|
||||||
);
|
);
|
||||||
ZMLockedPacket *starting_packet_lock = nullptr;
|
ZMLockedPacket *starting_packet_lock = nullptr;
|
||||||
ZMPacket *starting_packet = nullptr;
|
std::shared_ptr<ZMPacket> starting_packet = nullptr;
|
||||||
if (*start_it != snap_it) {
|
if (*start_it != snap_it) {
|
||||||
starting_packet_lock = packetqueue.get_packet(start_it);
|
starting_packet_lock = packetqueue.get_packet(start_it);
|
||||||
if (!starting_packet_lock) return false;
|
if (!starting_packet_lock) return false;
|
||||||
|
@ -2115,7 +2054,7 @@ bool Monitor::Analyse() {
|
||||||
starting_packet = snap;
|
starting_packet = snap;
|
||||||
}
|
}
|
||||||
|
|
||||||
event = new Event(this, *(starting_packet->timestamp), cause, noteSetMap);
|
event = new Event(this, starting_packet->timestamp, cause, noteSetMap);
|
||||||
shared_data->last_event_id = event->Id();
|
shared_data->last_event_id = event->Id();
|
||||||
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
||||||
video_store_data->recording = event->StartTime();
|
video_store_data->recording = event->StartTime();
|
||||||
|
@ -2522,13 +2461,17 @@ std::vector<std::shared_ptr<Monitor>> Monitor::LoadFfmpegMonitors(const char *fi
|
||||||
int Monitor::Capture() {
|
int Monitor::Capture() {
|
||||||
unsigned int index = image_count % image_buffer_count;
|
unsigned int index = image_count % image_buffer_count;
|
||||||
|
|
||||||
ZMPacket *packet = new ZMPacket();
|
Debug(1, "Packeet");
|
||||||
packet->timestamp = new struct timeval;
|
std::shared_ptr<ZMPacket> packet = std::make_shared<ZMPacket>();
|
||||||
|
//= new ZMPacket();
|
||||||
|
//packet->timestamp = new struct timeval;
|
||||||
packet->image_index = image_count;
|
packet->image_index = image_count;
|
||||||
gettimeofday(packet->timestamp, nullptr);
|
Debug(1, "Packeet");
|
||||||
shared_data->zmc_heartbeat_time = packet->timestamp->tv_sec;
|
gettimeofday(&(packet->timestamp), nullptr);
|
||||||
|
Debug(1, "Packeet");
|
||||||
int captureResult = camera->Capture(*packet);
|
shared_data->zmc_heartbeat_time = packet->timestamp.tv_sec;
|
||||||
|
Debug(1, "Capturing");
|
||||||
|
int captureResult = camera->Capture(packet);
|
||||||
Debug(4, "Back from capture result=%d image count %d", captureResult, image_count);
|
Debug(4, "Back from capture result=%d image count %d", captureResult, image_count);
|
||||||
|
|
||||||
if (captureResult < 0) {
|
if (captureResult < 0) {
|
||||||
|
@ -2543,24 +2486,24 @@ int Monitor::Capture() {
|
||||||
capture_image->Fill(signalcolor);
|
capture_image->Fill(signalcolor);
|
||||||
shared_data->signal = false;
|
shared_data->signal = false;
|
||||||
shared_data->last_write_index = index;
|
shared_data->last_write_index = index;
|
||||||
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
shared_data->last_write_time = shared_timestamps[index].tv_sec;
|
||||||
image_buffer[index].image->Assign(*capture_image);
|
image_buffer[index]->Assign(*capture_image);
|
||||||
*(image_buffer[index].timestamp) = *(packet->timestamp);
|
shared_timestamps[index] = packet->timestamp;
|
||||||
delete capture_image;
|
delete capture_image;
|
||||||
image_count++;
|
image_count++;
|
||||||
delete packet;
|
//delete packet;
|
||||||
// What about timestamping it?
|
// What about timestamping it?
|
||||||
// Don't want to do analysis on it, but we won't due to signal
|
// Don't want to do analysis on it, but we won't due to signal
|
||||||
return -1;
|
return -1;
|
||||||
} else if ( captureResult > 0 ) {
|
} else if (captureResult > 0) {
|
||||||
shared_data->signal = true; // Assume if getting packets that we are getting something useful. CheckSignalPoints can correct this later.
|
shared_data->signal = true; // Assume if getting packets that we are getting something useful. CheckSignalPoints can correct this later.
|
||||||
// If we captured, let's assume signal, Decode will detect further
|
// If we captured, let's assume signal, Decode will detect further
|
||||||
if (!decoding_enabled) {
|
if (!decoding_enabled) {
|
||||||
shared_data->last_write_index = index;
|
shared_data->last_write_index = index;
|
||||||
shared_data->last_write_time = packet->timestamp->tv_sec;
|
shared_data->last_write_time = packet->timestamp.tv_sec;
|
||||||
}
|
}
|
||||||
Debug(2, "Have packet stream_index:%d ?= videostream_id: %d q.vpktcount %d event? %d image_count %d",
|
Debug(2, "Have packet stream_index:%d ?= videostream_id: %d q.vpktcount %d event? %d image_count %d",
|
||||||
packet->packet.stream_index, video_stream_id, packetqueue.packet_count(video_stream_id), ( event ? 1 : 0 ), image_count );
|
packet->packet.stream_index, video_stream_id, packetqueue.packet_count(video_stream_id), ( event ? 1 : 0 ), image_count);
|
||||||
|
|
||||||
if (packet->codec_type == AVMEDIA_TYPE_VIDEO) {
|
if (packet->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
packet->packet.stream_index = video_stream_id; // Convert to packetQueue's index
|
packet->packet.stream_index = video_stream_id; // Convert to packetQueue's index
|
||||||
|
@ -2590,14 +2533,14 @@ int Monitor::Capture() {
|
||||||
packetqueue.queuePacket(packet);
|
packetqueue.queuePacket(packet);
|
||||||
} else {
|
} else {
|
||||||
Debug(4, "Not Queueing audio packet");
|
Debug(4, "Not Queueing audio packet");
|
||||||
delete packet;
|
//delete packet;
|
||||||
}
|
}
|
||||||
// Don't update last_write_index because that is used for live streaming
|
// Don't update last_write_index because that is used for live streaming
|
||||||
//shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
//shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "Unknown codec type %d", packet->codec_type);
|
Debug(1, "Unknown codec type %d", packet->codec_type);
|
||||||
delete packet;
|
//delete packet;
|
||||||
return 1;
|
return 1;
|
||||||
} // end if audio
|
} // end if audio
|
||||||
|
|
||||||
|
@ -2605,12 +2548,12 @@ int Monitor::Capture() {
|
||||||
|
|
||||||
// Will only be queued if there are iterators allocated in the queue.
|
// Will only be queued if there are iterators allocated in the queue.
|
||||||
if ( !packetqueue.queuePacket(packet) ) {
|
if ( !packetqueue.queuePacket(packet) ) {
|
||||||
delete packet;
|
//delete packet;
|
||||||
}
|
}
|
||||||
UpdateCaptureFPS();
|
UpdateCaptureFPS();
|
||||||
} else { // result == 0
|
} else { // result == 0
|
||||||
// Question is, do we update last_write_index etc?
|
// Question is, do we update last_write_index etc?
|
||||||
delete packet;
|
//delete packet;
|
||||||
return 0;
|
return 0;
|
||||||
} // end if result
|
} // end if result
|
||||||
|
|
||||||
|
@ -2635,7 +2578,7 @@ int Monitor::Capture() {
|
||||||
bool Monitor::Decode() {
|
bool Monitor::Decode() {
|
||||||
ZMLockedPacket *packet_lock = packetqueue.get_packet(decoder_it);
|
ZMLockedPacket *packet_lock = packetqueue.get_packet(decoder_it);
|
||||||
if (!packet_lock) return false;
|
if (!packet_lock) return false;
|
||||||
ZMPacket *packet = packet_lock->packet_;
|
std::shared_ptr<ZMPacket> packet = packet_lock->packet_;
|
||||||
packetqueue.increment_it(decoder_it);
|
packetqueue.increment_it(decoder_it);
|
||||||
if (packet->codec_type != AVMEDIA_TYPE_VIDEO) {
|
if (packet->codec_type != AVMEDIA_TYPE_VIDEO) {
|
||||||
Debug(4, "Not video");
|
Debug(4, "Not video");
|
||||||
|
@ -2758,25 +2701,25 @@ bool Monitor::Decode() {
|
||||||
TimestampImage(packet->image, packet->timestamp);
|
TimestampImage(packet->image, packet->timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
image_buffer[index].image->Assign(*(packet->image));
|
image_buffer[index]->Assign(*(packet->image));
|
||||||
*(image_buffer[index].timestamp) = *(packet->timestamp);
|
shared_timestamps[index] = packet->timestamp;
|
||||||
} // end if have image
|
} // end if have image
|
||||||
packet->decoded = true;
|
packet->decoded = true;
|
||||||
shared_data->signal = ( capture_image and signal_check_points ) ? CheckSignal(capture_image) : true;
|
shared_data->signal = ( capture_image and signal_check_points ) ? CheckSignal(capture_image) : true;
|
||||||
shared_data->last_write_index = index;
|
shared_data->last_write_index = index;
|
||||||
shared_data->last_write_time = packet->timestamp->tv_sec;
|
shared_data->last_write_time = packet->timestamp.tv_sec;
|
||||||
packetqueue.unlock(packet_lock);
|
packetqueue.unlock(packet_lock);
|
||||||
return true;
|
return true;
|
||||||
} // end bool Monitor::Decode()
|
} // end bool Monitor::Decode()
|
||||||
|
|
||||||
void Monitor::TimestampImage(Image *ts_image, const struct timeval *ts_time) const {
|
void Monitor::TimestampImage(Image *ts_image, const timeval &ts_time) const {
|
||||||
if ( !label_format[0] )
|
if ( !label_format[0] )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Expand the strftime macros first
|
// Expand the strftime macros first
|
||||||
char label_time_text[256];
|
char label_time_text[256];
|
||||||
tm ts_tm = {};
|
tm ts_tm = {};
|
||||||
strftime(label_time_text, sizeof(label_time_text), label_format.c_str(), localtime_r(&ts_time->tv_sec, &ts_tm));
|
strftime(label_time_text, sizeof(label_time_text), label_format.c_str(), localtime_r(&ts_time.tv_sec, &ts_tm));
|
||||||
char label_text[1024];
|
char label_text[1024];
|
||||||
const char *s_ptr = label_time_text;
|
const char *s_ptr = label_time_text;
|
||||||
char *d_ptr = label_text;
|
char *d_ptr = label_text;
|
||||||
|
@ -2793,7 +2736,7 @@ void Monitor::TimestampImage(Image *ts_image, const struct timeval *ts_time) con
|
||||||
found_macro = true;
|
found_macro = true;
|
||||||
break;
|
break;
|
||||||
case 'f' :
|
case 'f' :
|
||||||
d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000);
|
d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time.tv_usec/10000);
|
||||||
found_macro = true;
|
found_macro = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3175,21 +3118,21 @@ void Monitor::get_ref_image() {
|
||||||
|
|
||||||
Debug(1, "Waiting for capture daemon lastwriteindex(%d) lastwritetime(%" PRIi64 ")",
|
Debug(1, "Waiting for capture daemon lastwriteindex(%d) lastwritetime(%" PRIi64 ")",
|
||||||
shared_data->last_write_index, static_cast<int64>(shared_data->last_write_time));
|
shared_data->last_write_index, static_cast<int64>(shared_data->last_write_time));
|
||||||
if ( snap_lock and ! snap_lock->packet_->image ) {
|
if (snap_lock and ! snap_lock->packet_->image) {
|
||||||
delete snap_lock;
|
delete snap_lock;
|
||||||
// can't analyse it anyways, incremement
|
// can't analyse it anyways, incremement
|
||||||
packetqueue.increment_it(analysis_it);
|
packetqueue.increment_it(analysis_it);
|
||||||
}
|
}
|
||||||
//usleep(10000);
|
//usleep(10000);
|
||||||
}
|
}
|
||||||
if ( zm_terminate )
|
if (zm_terminate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ZMPacket *snap = snap_lock->packet_;
|
std::shared_ptr<ZMPacket> snap = snap_lock->packet_;
|
||||||
Debug(1, "get_ref_image: packet.stream %d ?= video_stream %d, packet image id %d packet image %p",
|
Debug(1, "get_ref_image: packet.stream %d ?= video_stream %d, packet image id %d packet image %p",
|
||||||
snap->packet.stream_index, video_stream_id, snap->image_index, snap->image );
|
snap->packet.stream_index, video_stream_id, snap->image_index, snap->image );
|
||||||
// Might not have been decoded yet FIXME
|
// Might not have been decoded yet FIXME
|
||||||
if ( snap->image ) {
|
if (snap->image) {
|
||||||
ref_image.Assign(width, height, camera->Colours(),
|
ref_image.Assign(width, height, camera->Colours(),
|
||||||
camera->SubpixelOrder(), snap->image->Buffer(), camera->ImageSize());
|
camera->SubpixelOrder(), snap->image->Buffer(), camera->ImageSize());
|
||||||
Debug(2, "Have ref image about to unlock");
|
Debug(2, "Have ref image about to unlock");
|
||||||
|
@ -3197,7 +3140,7 @@ void Monitor::get_ref_image() {
|
||||||
Debug(2, "Have no ref image about to unlock");
|
Debug(2, "Have no ref image about to unlock");
|
||||||
}
|
}
|
||||||
delete snap_lock;
|
delete snap_lock;
|
||||||
}
|
} // get_ref_image
|
||||||
|
|
||||||
std::vector<Group *> Monitor::Groups() {
|
std::vector<Group *> Monitor::Groups() {
|
||||||
// At the moment, only load groups once.
|
// At the moment, only load groups once.
|
||||||
|
|
|
@ -376,8 +376,7 @@ protected:
|
||||||
|
|
||||||
struct timeval *shared_timestamps;
|
struct timeval *shared_timestamps;
|
||||||
unsigned char *shared_images;
|
unsigned char *shared_images;
|
||||||
ZMPacket *image_buffer;
|
std::vector<Image *> image_buffer;
|
||||||
ZMPacket next_buffer; /* Used by four field deinterlacing */
|
|
||||||
|
|
||||||
int video_stream_id; // will be filled in PrimeCapture
|
int video_stream_id; // will be filled in PrimeCapture
|
||||||
int audio_stream_id; // will be filled in PrimeCapture
|
int audio_stream_id; // will be filled in PrimeCapture
|
||||||
|
@ -583,7 +582,7 @@ public:
|
||||||
bool Analyse();
|
bool Analyse();
|
||||||
bool Decode();
|
bool Decode();
|
||||||
void DumpImage( Image *dump_image ) const;
|
void DumpImage( Image *dump_image ) const;
|
||||||
void TimestampImage( Image *ts_image, const struct timeval *ts_time ) const;
|
void TimestampImage(Image *ts_image, const timeval &ts_time) const;
|
||||||
void closeEvent();
|
void closeEvent();
|
||||||
|
|
||||||
void Reload();
|
void Reload();
|
||||||
|
|
|
@ -320,13 +320,13 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
|
||||||
//updateFrameRate(monitor->GetFPS());
|
//updateFrameRate(monitor->GetFPS());
|
||||||
} // end void MonitorStream::processCommand(const CmdMsg *msg)
|
} // end void MonitorStream::processCommand(const CmdMsg *msg)
|
||||||
|
|
||||||
bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
|
bool MonitorStream::sendFrame(const char *filepath, const timeval ×tamp) {
|
||||||
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE));
|
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE));
|
||||||
|
|
||||||
if (
|
if (
|
||||||
( type != STREAM_JPEG )
|
( type != STREAM_JPEG )
|
||||||
||
|
||
|
||||||
( (!config.timestamp_on_capture) && timestamp )
|
(!config.timestamp_on_capture)
|
||||||
)
|
)
|
||||||
send_raw = false;
|
send_raw = false;
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
||||||
img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec))
|
img_buffer_size, (int)timestamp.tv_sec, (int)timestamp.tv_usec))
|
||||||
||
|
||
|
||||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||||
) {
|
) {
|
||||||
|
@ -379,9 +379,9 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
|
||||||
return false;
|
return false;
|
||||||
} // end bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp)
|
} // end bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp)
|
||||||
|
|
||||||
bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
bool MonitorStream::sendFrame(Image *image, const timeval ×tamp) {
|
||||||
Image *send_image = prepareImage(image);
|
Image *send_image = prepareImage(image);
|
||||||
if ( !config.timestamp_on_capture && timestamp )
|
if (!config.timestamp_on_capture)
|
||||||
monitor->TimestampImage(send_image, timestamp);
|
monitor->TimestampImage(send_image, timestamp);
|
||||||
|
|
||||||
fputs("--" BOUNDARY "\r\n", stdout);
|
fputs("--" BOUNDARY "\r\n", stdout);
|
||||||
|
@ -395,8 +395,8 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
||||||
static struct timeval base_time;
|
static struct timeval base_time;
|
||||||
struct DeltaTimeval delta_time;
|
struct DeltaTimeval delta_time;
|
||||||
if ( !frame_count )
|
if ( !frame_count )
|
||||||
base_time = *timestamp;
|
base_time = timestamp;
|
||||||
DELTA_TIMEVAL(delta_time, *timestamp, base_time, DT_PREC_3);
|
DELTA_TIMEVAL(delta_time, timestamp, base_time, DT_PREC_3);
|
||||||
/* double pts = */ vid_stream->EncodeFrame(send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_time.delta);
|
/* double pts = */ vid_stream->EncodeFrame(send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_time.delta);
|
||||||
} else
|
} else
|
||||||
#endif // HAVE_LIBAVCODEC
|
#endif // HAVE_LIBAVCODEC
|
||||||
|
@ -437,7 +437,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
( 0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
( 0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
||||||
img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec) )
|
img_buffer_size, (int)timestamp.tv_sec, (int)timestamp.tv_usec) )
|
||||||
||
|
||
|
||||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||||
) {
|
) {
|
||||||
|
@ -462,7 +462,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
||||||
} // Not mpeg
|
} // Not mpeg
|
||||||
last_frame_sent = TV_2_FLOAT(now);
|
last_frame_sent = TV_2_FLOAT(now);
|
||||||
return true;
|
return true;
|
||||||
} // end bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp )
|
} // end bool MonitorStream::sendFrame( Image *image, const timeval ×tamp )
|
||||||
|
|
||||||
void MonitorStream::runStream() {
|
void MonitorStream::runStream() {
|
||||||
if (type == STREAM_SINGLE) {
|
if (type == STREAM_SINGLE) {
|
||||||
|
@ -595,8 +595,8 @@ void MonitorStream::runStream() {
|
||||||
if ( !was_paused ) {
|
if ( !was_paused ) {
|
||||||
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
|
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
|
||||||
Debug(1, "Saving paused image from index %d",index);
|
Debug(1, "Saving paused image from index %d",index);
|
||||||
paused_image = new Image(*monitor->image_buffer[index].image);
|
paused_image = new Image(*monitor->image_buffer[index]);
|
||||||
paused_timestamp = *(monitor->image_buffer[index].timestamp);
|
paused_timestamp = monitor->shared_timestamps[index];
|
||||||
}
|
}
|
||||||
} else if ( paused_image ) {
|
} else if ( paused_image ) {
|
||||||
Debug(1, "Clearing paused_image");
|
Debug(1, "Clearing paused_image");
|
||||||
|
@ -635,7 +635,7 @@ void MonitorStream::runStream() {
|
||||||
if ( temp_index%frame_mod == 0 ) {
|
if ( temp_index%frame_mod == 0 ) {
|
||||||
Debug(2, "Sending delayed frame %d", temp_index);
|
Debug(2, "Sending delayed frame %d", temp_index);
|
||||||
// Send the next frame
|
// Send the next frame
|
||||||
if ( ! sendFrame(temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp) ) {
|
if (!sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp)) {
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
}
|
}
|
||||||
memcpy(&last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp));
|
memcpy(&last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp));
|
||||||
|
@ -652,7 +652,7 @@ void MonitorStream::runStream() {
|
||||||
// Send the next frame
|
// Send the next frame
|
||||||
if ( !sendFrame(
|
if ( !sendFrame(
|
||||||
temp_image_buffer[temp_read_index].file_name,
|
temp_image_buffer[temp_read_index].file_name,
|
||||||
&temp_image_buffer[temp_read_index].timestamp
|
temp_image_buffer[temp_read_index].timestamp
|
||||||
) ) {
|
) ) {
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
}
|
}
|
||||||
|
@ -672,7 +672,7 @@ void MonitorStream::runStream() {
|
||||||
// Send keepalive
|
// Send keepalive
|
||||||
Debug(2, "Sending keepalive frame %d", temp_index);
|
Debug(2, "Sending keepalive frame %d", temp_index);
|
||||||
// Send the next frame
|
// Send the next frame
|
||||||
if ( !sendFrame(temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp) ) {
|
if ( !sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp) ) {
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
}
|
}
|
||||||
// frame_sent = true;
|
// frame_sent = true;
|
||||||
|
@ -701,21 +701,21 @@ void MonitorStream::runStream() {
|
||||||
index, frame_mod, frame_count, paused, delayed);
|
index, frame_mod, frame_count, paused, delayed);
|
||||||
// Send the next frame
|
// Send the next frame
|
||||||
//
|
//
|
||||||
ZMPacket *snap = &monitor->image_buffer[index];
|
// Perhaps we should use NOW instead.
|
||||||
|
last_frame_timestamp = monitor->shared_timestamps[index];
|
||||||
|
Image *image = monitor->image_buffer[index];
|
||||||
|
|
||||||
if ( !sendFrame(snap->image, snap->timestamp) ) {
|
if ( !sendFrame(image, last_frame_timestamp) ) {
|
||||||
Debug(2, "sendFrame failed, quiting.");
|
Debug(2, "sendFrame failed, quiting.");
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Perhaps we should use NOW instead.
|
|
||||||
last_frame_timestamp = *(snap->timestamp);
|
|
||||||
//frame_sent = true;
|
//frame_sent = true;
|
||||||
//
|
//
|
||||||
if ( frame_count == 0 ) {
|
if ( frame_count == 0 ) {
|
||||||
// Chrome will not display the first frame until it receives another.
|
// Chrome will not display the first frame until it receives another.
|
||||||
// Firefox is fine. So just send the first frame twice.
|
// Firefox is fine. So just send the first frame twice.
|
||||||
if ( !sendFrame(snap->image, snap->timestamp) ) {
|
if ( !sendFrame(image, last_frame_timestamp) ) {
|
||||||
Debug(2, "sendFrame failed, quiting.");
|
Debug(2, "sendFrame failed, quiting.");
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
break;
|
break;
|
||||||
|
@ -730,9 +730,9 @@ void MonitorStream::runStream() {
|
||||||
}
|
}
|
||||||
if ( last_zoom != zoom ) {
|
if ( last_zoom != zoom ) {
|
||||||
Debug(2, "Sending 2 frames because change in zoom %d ?= %d", last_zoom, zoom);
|
Debug(2, "Sending 2 frames because change in zoom %d ?= %d", last_zoom, zoom);
|
||||||
if ( !sendFrame(paused_image, &paused_timestamp) )
|
if (!sendFrame(paused_image, paused_timestamp))
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
if ( !sendFrame(paused_image, &paused_timestamp) )
|
if (!sendFrame(paused_image, paused_timestamp))
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
} else {
|
} else {
|
||||||
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
|
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
|
||||||
|
@ -742,7 +742,7 @@ void MonitorStream::runStream() {
|
||||||
Debug(2, "Sending keepalive frame because delta time %.2f > 5",
|
Debug(2, "Sending keepalive frame because delta time %.2f > 5",
|
||||||
actual_delta_time);
|
actual_delta_time);
|
||||||
// Send the next frame
|
// Send the next frame
|
||||||
if ( !sendFrame(paused_image, &paused_timestamp) )
|
if (!sendFrame(paused_image, paused_timestamp))
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
} else {
|
} else {
|
||||||
Debug(2, "Would have sent keepalive frame, but had no paused_image");
|
Debug(2, "Would have sent keepalive frame, but had no paused_image");
|
||||||
|
@ -767,7 +767,7 @@ void MonitorStream::runStream() {
|
||||||
temp_image_buffer[temp_index].valid = true;
|
temp_image_buffer[temp_index].valid = true;
|
||||||
}
|
}
|
||||||
temp_image_buffer[temp_index].timestamp = monitor->shared_timestamps[index];
|
temp_image_buffer[temp_index].timestamp = monitor->shared_timestamps[index];
|
||||||
monitor->image_buffer[index].image->WriteJpeg(
|
monitor->image_buffer[index]->WriteJpeg(
|
||||||
temp_image_buffer[temp_index].file_name,
|
temp_image_buffer[temp_index].file_name,
|
||||||
config.jpeg_file_quality
|
config.jpeg_file_quality
|
||||||
);
|
);
|
||||||
|
@ -865,8 +865,7 @@ void MonitorStream::SingleImage(int scale) {
|
||||||
}
|
}
|
||||||
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
|
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
|
||||||
Debug(1, "write index: %d %d", monitor->shared_data->last_write_index, index);
|
Debug(1, "write index: %d %d", monitor->shared_data->last_write_index, index);
|
||||||
ZMPacket *snap = &(monitor->image_buffer[index]);
|
Image *snap_image = monitor->image_buffer[index];
|
||||||
Image *snap_image = snap->image;
|
|
||||||
|
|
||||||
if ( scale != ZM_SCALE_BASE ) {
|
if ( scale != ZM_SCALE_BASE ) {
|
||||||
scaled_image.Assign(*snap_image);
|
scaled_image.Assign(*snap_image);
|
||||||
|
@ -874,7 +873,7 @@ void MonitorStream::SingleImage(int scale) {
|
||||||
snap_image = &scaled_image;
|
snap_image = &scaled_image;
|
||||||
}
|
}
|
||||||
if ( !config.timestamp_on_capture ) {
|
if ( !config.timestamp_on_capture ) {
|
||||||
monitor->TimestampImage(snap_image, snap->timestamp);
|
monitor->TimestampImage(snap_image, monitor->shared_timestamps[index]);
|
||||||
}
|
}
|
||||||
snap_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
snap_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,8 @@ class MonitorStream : public StreamBase {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool checkSwapPath(const char *path, bool create_path);
|
bool checkSwapPath(const char *path, bool create_path);
|
||||||
bool sendFrame(const char *filepath, struct timeval *timestamp);
|
bool sendFrame(const char *filepath, const timeval ×tamp);
|
||||||
bool sendFrame(Image *image, struct timeval *timestamp);
|
bool sendFrame(Image *image, const timeval ×tamp);
|
||||||
void processCommand(const CmdMsg *msg) override;
|
void processCommand(const CmdMsg *msg) override;
|
||||||
void SingleImage(int scale=100);
|
void SingleImage(int scale=100);
|
||||||
void SingleImageRaw(int scale=100);
|
void SingleImageRaw(int scale=100);
|
||||||
|
|
|
@ -31,7 +31,7 @@ ZMPacket::ZMPacket() :
|
||||||
stream(nullptr),
|
stream(nullptr),
|
||||||
in_frame(nullptr),
|
in_frame(nullptr),
|
||||||
out_frame(nullptr),
|
out_frame(nullptr),
|
||||||
timestamp(nullptr),
|
timestamp({}),
|
||||||
buffer(nullptr),
|
buffer(nullptr),
|
||||||
image(nullptr),
|
image(nullptr),
|
||||||
analysis_image(nullptr),
|
analysis_image(nullptr),
|
||||||
|
@ -41,6 +41,28 @@ ZMPacket::ZMPacket() :
|
||||||
codec_imgsize(0),
|
codec_imgsize(0),
|
||||||
pts(0),
|
pts(0),
|
||||||
decoded(0)
|
decoded(0)
|
||||||
|
{
|
||||||
|
Debug(1, "ZMPacket");
|
||||||
|
av_init_packet(&packet);
|
||||||
|
packet.size = 0; // So we can detect whether it has been filled.
|
||||||
|
Debug(1, "ZMPacket");
|
||||||
|
}
|
||||||
|
|
||||||
|
ZMPacket::ZMPacket(Image *i, const timeval &tv) :
|
||||||
|
keyframe(0),
|
||||||
|
stream(nullptr),
|
||||||
|
in_frame(nullptr),
|
||||||
|
out_frame(nullptr),
|
||||||
|
timestamp(tv),
|
||||||
|
buffer(nullptr),
|
||||||
|
image(i),
|
||||||
|
analysis_image(nullptr),
|
||||||
|
score(-1),
|
||||||
|
codec_type(AVMEDIA_TYPE_UNKNOWN),
|
||||||
|
image_index(-1),
|
||||||
|
codec_imgsize(0),
|
||||||
|
pts(0),
|
||||||
|
decoded(0)
|
||||||
{
|
{
|
||||||
av_init_packet(&packet);
|
av_init_packet(&packet);
|
||||||
packet.size = 0; // So we can detect whether it has been filled.
|
packet.size = 0; // So we can detect whether it has been filled.
|
||||||
|
@ -51,7 +73,7 @@ ZMPacket::ZMPacket(ZMPacket &p) :
|
||||||
stream(nullptr),
|
stream(nullptr),
|
||||||
in_frame(nullptr),
|
in_frame(nullptr),
|
||||||
out_frame(nullptr),
|
out_frame(nullptr),
|
||||||
timestamp(nullptr),
|
timestamp(p.timestamp),
|
||||||
buffer(nullptr),
|
buffer(nullptr),
|
||||||
image(nullptr),
|
image(nullptr),
|
||||||
analysis_image(nullptr),
|
analysis_image(nullptr),
|
||||||
|
@ -68,18 +90,15 @@ ZMPacket::ZMPacket(ZMPacket &p) :
|
||||||
if ( zm_av_packet_ref(&packet, &p.packet) < 0 ) {
|
if ( zm_av_packet_ref(&packet, &p.packet) < 0 ) {
|
||||||
Error("error refing packet");
|
Error("error refing packet");
|
||||||
}
|
}
|
||||||
timestamp = new struct timeval;
|
|
||||||
*timestamp = *p.timestamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket::~ZMPacket() {
|
ZMPacket::~ZMPacket() {
|
||||||
zm_av_packet_unref(&packet);
|
zm_av_packet_unref(&packet);
|
||||||
if ( in_frame ) av_frame_free(&in_frame);
|
if (in_frame) av_frame_free(&in_frame);
|
||||||
if ( out_frame ) av_frame_free(&out_frame);
|
if (out_frame) av_frame_free(&out_frame);
|
||||||
if ( buffer ) av_freep(&buffer);
|
if (buffer) av_freep(&buffer);
|
||||||
if ( analysis_image ) delete analysis_image;
|
if (analysis_image) delete analysis_image;
|
||||||
if ( image ) delete image;
|
if (image) delete image;
|
||||||
if ( timestamp ) delete timestamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns < 0 on error, 0 on not ready, int bytes consumed on success
|
/* returns < 0 on error, 0 on not ready, int bytes consumed on success
|
||||||
|
@ -227,7 +246,7 @@ AVPacket *ZMPacket::set_packet(AVPacket *p) {
|
||||||
Error("error refing packet");
|
Error("error refing packet");
|
||||||
}
|
}
|
||||||
//ZM_DUMP_PACKET(packet, "zmpacket:");
|
//ZM_DUMP_PACKET(packet, "zmpacket:");
|
||||||
gettimeofday(timestamp, nullptr);
|
gettimeofday(×tamp, nullptr);
|
||||||
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
||||||
return &packet;
|
return &packet;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ class ZMPacket {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
// The condition has to be in the packet because it is shared between locks
|
||||||
std::condition_variable condition_;
|
std::condition_variable condition_;
|
||||||
|
|
||||||
int keyframe;
|
int keyframe;
|
||||||
|
@ -48,7 +49,7 @@ class ZMPacket {
|
||||||
AVPacket packet; // Input packet, undecoded
|
AVPacket packet; // Input packet, undecoded
|
||||||
AVFrame *in_frame; // Input image, decoded Theoretically only filled if needed.
|
AVFrame *in_frame; // Input image, decoded Theoretically only filled if needed.
|
||||||
AVFrame *out_frame; // output image, Only filled if needed.
|
AVFrame *out_frame; // output image, Only filled if needed.
|
||||||
struct timeval *timestamp;
|
timeval timestamp;
|
||||||
uint8_t *buffer; // buffer used in image
|
uint8_t *buffer; // buffer used in image
|
||||||
Image *image;
|
Image *image;
|
||||||
Image *analysis_image;
|
Image *analysis_image;
|
||||||
|
@ -69,7 +70,7 @@ class ZMPacket {
|
||||||
|
|
||||||
int is_keyframe() { return keyframe; };
|
int is_keyframe() { return keyframe; };
|
||||||
int decode( AVCodecContext *ctx );
|
int decode( AVCodecContext *ctx );
|
||||||
explicit ZMPacket(Image *image);
|
explicit ZMPacket(Image *image, const timeval &tv);
|
||||||
explicit ZMPacket(ZMPacket &packet);
|
explicit ZMPacket(ZMPacket &packet);
|
||||||
ZMPacket();
|
ZMPacket();
|
||||||
~ZMPacket();
|
~ZMPacket();
|
||||||
|
@ -81,11 +82,11 @@ class ZMPacket {
|
||||||
|
|
||||||
class ZMLockedPacket {
|
class ZMLockedPacket {
|
||||||
public:
|
public:
|
||||||
ZMPacket *packet_;
|
std::shared_ptr<ZMPacket> packet_;
|
||||||
std::unique_lock<std::mutex> lck_;
|
std::unique_lock<std::mutex> lck_;
|
||||||
bool locked;
|
bool locked;
|
||||||
|
|
||||||
explicit ZMLockedPacket(ZMPacket *p) :
|
explicit ZMLockedPacket(std::shared_ptr<ZMPacket> p) :
|
||||||
packet_(p),
|
packet_(p),
|
||||||
lck_(packet_->mutex_, std::defer_lock),
|
lck_(packet_->mutex_, std::defer_lock),
|
||||||
locked(false) {
|
locked(false) {
|
||||||
|
|
|
@ -75,8 +75,7 @@ PacketQueue::~PacketQueue() {
|
||||||
* Thus it will ensure that the same packet never gets queued twice.
|
* Thus it will ensure that the same packet never gets queued twice.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool PacketQueue::queuePacket(ZMPacket* add_packet) {
|
bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
||||||
Debug(4, "packetqueue queuepacket %p %d", add_packet, add_packet->image_index);
|
|
||||||
if (iterators.empty()) {
|
if (iterators.empty()) {
|
||||||
Debug(4, "No iterators so no one needs us to queue packets.");
|
Debug(4, "No iterators so no one needs us to queue packets.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -97,7 +96,7 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) {
|
||||||
if (add_packet->keyframe) {
|
if (add_packet->keyframe) {
|
||||||
// Have a new keyframe, so delete everything
|
// Have a new keyframe, so delete everything
|
||||||
while ((*pktQueue.begin() != add_packet) and (packet_counts[video_stream_id] > max_video_packet_count)) {
|
while ((*pktQueue.begin() != add_packet) and (packet_counts[video_stream_id] > max_video_packet_count)) {
|
||||||
ZMPacket *zm_packet = *pktQueue.begin();
|
std::shared_ptr <ZMPacket>zm_packet = *pktQueue.begin();
|
||||||
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
|
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
|
||||||
if (!lp->trylock()) {
|
if (!lp->trylock()) {
|
||||||
Debug(1, "Found locked packet when trying to free up video packets. Can't continue");
|
Debug(1, "Found locked packet when trying to free up video packets. Can't continue");
|
||||||
|
@ -129,7 +128,6 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) {
|
||||||
packet_counts[video_stream_id],
|
packet_counts[video_stream_id],
|
||||||
max_video_packet_count,
|
max_video_packet_count,
|
||||||
pktQueue.size());
|
pktQueue.size());
|
||||||
delete zm_packet;
|
|
||||||
} // end while
|
} // end while
|
||||||
}
|
}
|
||||||
} // end if too many video packets
|
} // end if too many video packets
|
||||||
|
@ -166,7 +164,7 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) {
|
||||||
return true;
|
return true;
|
||||||
} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet)
|
} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet)
|
||||||
|
|
||||||
void PacketQueue::clearPackets(ZMPacket *add_packet) {
|
void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||||
// Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one.
|
// 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:
|
// No good. Have to satisfy two conditions:
|
||||||
// 1. packetqueue starts with a video keyframe
|
// 1. packetqueue starts with a video keyframe
|
||||||
|
@ -211,7 +209,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] > pre_event_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();
|
std::shared_ptr<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;
|
||||||
delete lp;
|
delete lp;
|
||||||
|
@ -231,7 +229,7 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
|
||||||
packet_counts[video_stream_id],
|
packet_counts[video_stream_id],
|
||||||
pre_event_video_packet_count,
|
pre_event_video_packet_count,
|
||||||
pktQueue.size());
|
pktQueue.size());
|
||||||
delete zm_packet;
|
//delete zm_packet;
|
||||||
} // end while
|
} // end while
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +239,11 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
|
||||||
int video_packets_to_delete = 0; // This is a count of how many packets we will delete so we know when to stop looking
|
int video_packets_to_delete = 0; // This is a count of how many packets we will delete so we know when to stop looking
|
||||||
|
|
||||||
// First packet is special because we know it is a video keyframe and only need to check for lock
|
// First packet is special because we know it is a video keyframe and only need to check for lock
|
||||||
ZMPacket *zm_packet = *it;
|
std::shared_ptr<ZMPacket> zm_packet = *it;
|
||||||
|
if (zm_packet == add_packet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Debug(1, "trying lock on first packet");
|
Debug(1, "trying lock on first packet");
|
||||||
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
|
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
|
||||||
if (lp->trylock()) {
|
if (lp->trylock()) {
|
||||||
|
@ -288,10 +290,10 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
|
||||||
( *it == add_packet ),
|
( *it == add_packet ),
|
||||||
( next_front == pktQueue.begin() )
|
( next_front == pktQueue.begin() )
|
||||||
);
|
);
|
||||||
if ( next_front != pktQueue.begin() ) {
|
if (next_front != pktQueue.begin()) {
|
||||||
while ( pktQueue.begin() != next_front ) {
|
while (pktQueue.begin() != next_front) {
|
||||||
ZMPacket *zm_packet = *pktQueue.begin();
|
std::shared_ptr<ZMPacket> zm_packet = *pktQueue.begin();
|
||||||
if ( !zm_packet ) {
|
if (!zm_packet) {
|
||||||
Error("NULL zm_packet in queue");
|
Error("NULL zm_packet in queue");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +308,7 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
|
||||||
pktQueue.size());
|
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;
|
||||||
}
|
}
|
||||||
} // end if have at least max_video_packet_count video packets remaining
|
} // end if have at least max_video_packet_count video packets remaining
|
||||||
// We signal on every packet because someday we may analyze sound
|
// We signal on every packet because someday we may analyze sound
|
||||||
|
@ -314,116 +316,6 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) {
|
||||||
return;
|
return;
|
||||||
} // end voidPacketQueue::clearPackets(ZMPacket* zm_packet)
|
} // end voidPacketQueue::clearPackets(ZMPacket* zm_packet)
|
||||||
|
|
||||||
ZMLockedPacket* PacketQueue::popPacket( ) {
|
|
||||||
Debug(4, "pktQueue size %zu", pktQueue.size());
|
|
||||||
if ( pktQueue.empty() ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
Debug(4, "poPacket Mutex locking");
|
|
||||||
std::unique_lock<std::mutex> lck(mutex);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
ZMLockedPacket *lp = new ZMLockedPacket (zm_packet);
|
|
||||||
lp->lock();
|
|
||||||
|
|
||||||
pktQueue.pop_front();
|
|
||||||
packet_counts[zm_packet->packet.stream_index] -= 1;
|
|
||||||
|
|
||||||
return lp;
|
|
||||||
} // popPacket
|
|
||||||
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned int PacketQueue::clear(unsigned int frames_to_keep, int stream_id) {
|
|
||||||
Debug(3, "Clearing all but %d frames, queue has %zu", frames_to_keep, pktQueue.size());
|
|
||||||
|
|
||||||
if ( pktQueue.empty() ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If size is <= frames_to_keep since it could contain audio, we can't possibly do anything
|
|
||||||
if ( pktQueue.size() <= frames_to_keep ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Debug(5, "Locking in clear");
|
|
||||||
std::unique_lock<std::mutex> lck(mutex);
|
|
||||||
|
|
||||||
packetqueue_iterator it = pktQueue.end()--; // point to last element instead of end
|
|
||||||
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 %zu",
|
|
||||||
delete_count, pktQueue.size());
|
|
||||||
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
|
|
||||||
packet_counts[zm_packet->packet.stream_index] --;
|
|
||||||
pktQueue.pop_front();
|
|
||||||
//if ( zm_packet->image_index == -1 )
|
|
||||||
delete zm_packet;
|
|
||||||
|
|
||||||
delete_count += 1;
|
|
||||||
} // while our iterator is not the first packet
|
|
||||||
Debug(3, "Deleted %d packets, %zu remaining", delete_count, pktQueue.size());
|
|
||||||
return delete_count;
|
|
||||||
} // end unsigned int PacketQueue::clear( unsigned int frames_to_keep, int stream_id )
|
|
||||||
|
|
||||||
void PacketQueue::clear() {
|
void PacketQueue::clear() {
|
||||||
deleting = true;
|
deleting = true;
|
||||||
condition.notify_all();
|
condition.notify_all();
|
||||||
|
@ -431,13 +323,13 @@ void PacketQueue::clear() {
|
||||||
std::unique_lock<std::mutex> lck(mutex);
|
std::unique_lock<std::mutex> lck(mutex);
|
||||||
|
|
||||||
while (!pktQueue.empty()) {
|
while (!pktQueue.empty()) {
|
||||||
ZMPacket *packet = pktQueue.front();
|
std::shared_ptr<ZMPacket> packet = pktQueue.front();
|
||||||
// Someone might have this packet, but not for very long and since we have locked the queue they won't be able to get another one
|
// Someone might have this packet, but not for very long and since we have locked the queue they won't be able to get another one
|
||||||
ZMLockedPacket *lp = new ZMLockedPacket(packet);
|
ZMLockedPacket *lp = new ZMLockedPacket(packet);
|
||||||
lp->lock();
|
lp->lock();
|
||||||
pktQueue.pop_front();
|
pktQueue.pop_front();
|
||||||
delete lp;
|
delete lp;
|
||||||
delete packet;
|
//delete packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (
|
for (
|
||||||
|
@ -449,119 +341,32 @@ void PacketQueue::clear() {
|
||||||
*iterator_it = pktQueue.begin();
|
*iterator_it = pktQueue.begin();
|
||||||
} // end foreach iterator
|
} // end foreach iterator
|
||||||
|
|
||||||
if ( packet_counts ) delete[] packet_counts;
|
if (packet_counts) delete[] packet_counts;
|
||||||
packet_counts = nullptr;
|
packet_counts = nullptr;
|
||||||
max_stream_id = -1;
|
max_stream_id = -1;
|
||||||
|
|
||||||
condition.notify_all();
|
condition.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear queue keeping only specified duration of video -- return number of pkts removed
|
|
||||||
unsigned int PacketQueue::clear(struct timeval *duration, int streamId) {
|
|
||||||
|
|
||||||
if ( pktQueue.empty() ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Debug(4, "Locking in clear");
|
|
||||||
std::unique_lock<std::mutex> lck(mutex);
|
|
||||||
|
|
||||||
struct timeval keep_from;
|
|
||||||
std::list<ZMPacket *>::reverse_iterator it = pktQueue.rbegin();
|
|
||||||
|
|
||||||
struct timeval *t = (*it)->timestamp;
|
|
||||||
timersub(t, duration, &keep_from);
|
|
||||||
++it;
|
|
||||||
|
|
||||||
Debug(3, "Looking for frame before queue keep time with stream id (%d), queue has %zu 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)
|
|
||||||
and
|
|
||||||
timercmp(zm_packet->timestamp, &keep_from, <=)
|
|
||||||
) {
|
|
||||||
Debug(3, "Found frame before keep time with stream index %d at %" PRIi64 ".%" PRIi64,
|
|
||||||
av_packet->stream_index,
|
|
||||||
static_cast<int64>(zm_packet->timestamp->tv_sec),
|
|
||||||
static_cast<int64>(zm_packet->timestamp->tv_usec));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( it == pktQueue.rend() ) {
|
|
||||||
Debug(1, "Didn't find a frame before queue preserve time. keeping all");
|
|
||||||
mutex.unlock();
|
|
||||||
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)
|
|
||||||
and
|
|
||||||
(av_packet->stream_index == streamId)
|
|
||||||
) {
|
|
||||||
Debug(3, "Found keyframe before start with stream index %d at %" PRIi64 ".%" PRIi64,
|
|
||||||
av_packet->stream_index,
|
|
||||||
static_cast<int64>(zm_packet->timestamp->tv_sec),
|
|
||||||
static_cast<int64>(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 = nullptr;
|
|
||||||
while ( distance(it, pktQueue.rend()) > 1 ) {
|
|
||||||
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
|
|
||||||
pktQueue.pop_front();
|
|
||||||
packet_counts[zm_packet->packet.stream_index] -= 1;
|
|
||||||
delete zm_packet;
|
|
||||||
deleted_frames += 1;
|
|
||||||
}
|
|
||||||
Debug(3, "Deleted %d frames", deleted_frames);
|
|
||||||
return deleted_frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int PacketQueue::size() {
|
unsigned int PacketQueue::size() {
|
||||||
return pktQueue.size();
|
return pktQueue.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int PacketQueue::packet_count(int stream_id) {
|
int PacketQueue::packet_count(int stream_id) {
|
||||||
if ( stream_id < 0 or stream_id > max_stream_id ) {
|
if (stream_id < 0 or stream_id > max_stream_id) {
|
||||||
Error("Invalid stream_id %d max is %d", stream_id, max_stream_id);
|
Error("Invalid stream_id %d max is %d", stream_id, max_stream_id);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return packet_counts[stream_id];
|
return packet_counts[stream_id];
|
||||||
} // end int PacketQueue::packet_count(int stream_id)
|
} // end int PacketQueue::packet_count(int stream_id)
|
||||||
|
|
||||||
|
|
||||||
// Returns a packet. Packet will be locked
|
// Returns a packet. Packet will be locked
|
||||||
ZMLockedPacket *PacketQueue::get_packet(packetqueue_iterator *it) {
|
ZMLockedPacket *PacketQueue::get_packet(packetqueue_iterator *it) {
|
||||||
if (deleting or zm_terminate)
|
if (deleting or zm_terminate)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Debug(4, "Locking in get_packet using it %p queue end? %d, packet %p",
|
Debug(4, "Locking in get_packet using it %p queue end? %d",
|
||||||
std::addressof(*it), (*it == pktQueue.end()), *(*it));
|
std::addressof(*it), (*it == pktQueue.end()));
|
||||||
std::unique_lock<std::mutex> lck(mutex);
|
std::unique_lock<std::mutex> lck(mutex);
|
||||||
Debug(4, "Have Lock in get_packet");
|
Debug(4, "Have Lock in get_packet");
|
||||||
|
|
||||||
|
@ -582,13 +387,13 @@ ZMLockedPacket *PacketQueue::get_packet(packetqueue_iterator *it) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket *p = *(*it);
|
std::shared_ptr<ZMPacket> p = *(*it);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
Error("Null p?!");
|
Error("Null p?!");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Debug(4, "get_packet using it %p locking index %d, packet %p",
|
Debug(4, "get_packet using it %p locking index %d",
|
||||||
std::addressof(*it), p->image_index, p);
|
std::addressof(*it), p->image_index);
|
||||||
// Packets are only deleted by packetqueue, so lock must be held.
|
// Packets are only deleted by packetqueue, so lock must be held.
|
||||||
// We shouldn't have to trylock. Someone else might hold the lock but not for long
|
// We shouldn't have to trylock. Someone else might hold the lock but not for long
|
||||||
|
|
||||||
|
@ -655,7 +460,7 @@ packetqueue_iterator *PacketQueue::get_event_start_packet_it(
|
||||||
iterators.push_back(it);
|
iterators.push_back(it);
|
||||||
|
|
||||||
*it = snapshot_it;
|
*it = snapshot_it;
|
||||||
ZMPacket *packet = *(*it);
|
std::shared_ptr<ZMPacket> packet = *(*it);
|
||||||
ZM_DUMP_PACKET(packet->packet, "");
|
ZM_DUMP_PACKET(packet->packet, "");
|
||||||
// Step one count back pre_event_count frames as the minimum
|
// Step one count back pre_event_count frames as the minimum
|
||||||
// Do not assume that snapshot_it is video
|
// Do not assume that snapshot_it is video
|
||||||
|
@ -702,9 +507,9 @@ packetqueue_iterator *PacketQueue::get_event_start_packet_it(
|
||||||
} // end packetqueue_iterator *PacketQueue::get_event_start_packet_it
|
} // end packetqueue_iterator *PacketQueue::get_event_start_packet_it
|
||||||
|
|
||||||
void PacketQueue::dumpQueue() {
|
void PacketQueue::dumpQueue() {
|
||||||
std::list<ZMPacket *>::reverse_iterator it;
|
std::list<std::shared_ptr<ZMPacket>>::reverse_iterator it;
|
||||||
for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) {
|
for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) {
|
||||||
ZMPacket *zm_packet = *it;
|
std::shared_ptr<ZMPacket> zm_packet = *it;
|
||||||
ZM_DUMP_PACKET(zm_packet->packet, "");
|
ZM_DUMP_PACKET(zm_packet->packet, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -732,8 +537,8 @@ packetqueue_iterator * PacketQueue::get_video_it(bool wait) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( *it != pktQueue.end() ) {
|
while (*it != pktQueue.end()) {
|
||||||
ZMPacket *zm_packet = *(*it);
|
std::shared_ptr<ZMPacket> zm_packet = *(*it);
|
||||||
if (!zm_packet) {
|
if (!zm_packet) {
|
||||||
Error("Null zmpacket in queue!?");
|
Error("Null zmpacket in queue!?");
|
||||||
free_it(it);
|
free_it(it);
|
||||||
|
@ -764,19 +569,19 @@ void PacketQueue::free_it(packetqueue_iterator *it) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PacketQueue::is_there_an_iterator_pointing_to_packet(ZMPacket *zm_packet) {
|
bool PacketQueue::is_there_an_iterator_pointing_to_packet(const std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
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() ) {
|
if (*iterator_it == pktQueue.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Debug(4, "Checking iterator %p == packet ? %d", std::addressof(*iterator_it), ( *(*iterator_it) == zm_packet ));
|
Debug(4, "Checking iterator %p == packet ? %d", std::addressof(*iterator_it), ( *(*iterator_it) == zm_packet ));
|
||||||
// Have to check each iterator and make sure it doesn't point to the packet we are about to delete
|
// 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 ) {
|
if (*(*iterator_it) == zm_packet) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // end foreach iterator
|
} // end foreach iterator
|
||||||
|
@ -786,13 +591,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 < 0 )
|
if (max_video_packet_count < 0)
|
||||||
max_video_packet_count = 0 ;
|
max_video_packet_count = 0 ;
|
||||||
}
|
}
|
||||||
void PacketQueue::setPreEventVideoPackets(int p) {
|
void PacketQueue::setPreEventVideoPackets(int p) {
|
||||||
pre_event_video_packet_count = p;
|
pre_event_video_packet_count = p;
|
||||||
Debug(1, "Setting pre_event_video_packet_count to %d", p);
|
Debug(1, "Setting pre_event_video_packet_count to %d", p);
|
||||||
if ( pre_event_video_packet_count < 1 )
|
if (pre_event_video_packet_count < 1)
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,12 @@
|
||||||
class ZMPacket;
|
class ZMPacket;
|
||||||
class ZMLockedPacket;
|
class ZMLockedPacket;
|
||||||
|
|
||||||
typedef std::list<ZMPacket *>::iterator packetqueue_iterator;
|
typedef std::list<std::shared_ptr<ZMPacket>>::iterator packetqueue_iterator;
|
||||||
|
|
||||||
class PacketQueue {
|
class PacketQueue {
|
||||||
public: // For now just to ease development
|
public: // For now just to ease development
|
||||||
std::list<ZMPacket *> pktQueue;
|
std::list<std::shared_ptr<ZMPacket>> pktQueue;
|
||||||
std::list<ZMPacket *>::iterator analysis_it;
|
std::list<std::shared_ptr<ZMPacket>>::iterator analysis_it;
|
||||||
|
|
||||||
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
|
||||||
|
@ -49,27 +49,21 @@ class PacketQueue {
|
||||||
public:
|
public:
|
||||||
PacketQueue();
|
PacketQueue();
|
||||||
virtual ~PacketQueue();
|
virtual ~PacketQueue();
|
||||||
std::list<ZMPacket *>::const_iterator end() const { return pktQueue.end(); }
|
std::list<std::shared_ptr<ZMPacket>>::const_iterator end() const { return pktQueue.end(); }
|
||||||
std::list<ZMPacket *>::const_iterator begin() const { return pktQueue.begin(); }
|
std::list<std::shared_ptr<ZMPacket>>::const_iterator begin() const { return pktQueue.begin(); }
|
||||||
|
|
||||||
int addStream();
|
int addStream();
|
||||||
void setMaxVideoPackets(int p);
|
void setMaxVideoPackets(int p);
|
||||||
void setPreEventVideoPackets(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(std::shared_ptr<ZMPacket> packet);
|
||||||
ZMLockedPacket * popPacket();
|
|
||||||
bool popVideoPacket(ZMPacket* packet);
|
|
||||||
bool popAudioPacket(ZMPacket* packet);
|
|
||||||
unsigned int clear(unsigned int video_frames_to_keep, int stream_id);
|
|
||||||
unsigned int clear(struct timeval *duration, int streamid);
|
|
||||||
void clear();
|
void clear();
|
||||||
void dumpQueue();
|
void dumpQueue();
|
||||||
unsigned int size();
|
unsigned int size();
|
||||||
unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; };
|
unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; };
|
||||||
|
|
||||||
void clear_unwanted_packets(timeval *recording, int pre_event_count, int mVideoStreamId);
|
void clearPackets(const std::shared_ptr<ZMPacket> &packet);
|
||||||
void clearPackets(ZMPacket *);
|
|
||||||
int packet_count(int stream_id);
|
int packet_count(int stream_id);
|
||||||
|
|
||||||
bool increment_it(packetqueue_iterator *it);
|
bool increment_it(packetqueue_iterator *it);
|
||||||
|
@ -83,7 +77,7 @@ class PacketQueue {
|
||||||
packetqueue_iterator snapshot_it,
|
packetqueue_iterator snapshot_it,
|
||||||
unsigned int pre_event_count
|
unsigned int pre_event_count
|
||||||
);
|
);
|
||||||
bool is_there_an_iterator_pointing_to_packet(ZMPacket *zm_packet);
|
bool is_there_an_iterator_pointing_to_packet(const std::shared_ptr<ZMPacket> &zm_packet);
|
||||||
void unlock(ZMLockedPacket *lp);
|
void unlock(ZMLockedPacket *lp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ public:
|
||||||
virtual int Disconnect() = 0;
|
virtual int Disconnect() = 0;
|
||||||
virtual int PreCapture() override { return 0; };
|
virtual int PreCapture() override { return 0; };
|
||||||
virtual int PrimeCapture() override { return 0; };
|
virtual int PrimeCapture() override { return 0; };
|
||||||
virtual int Capture(ZMPacket &p) override = 0;
|
virtual int Capture(std::shared_ptr<ZMPacket> &p) override = 0;
|
||||||
virtual int PostCapture() override = 0;
|
virtual int PostCapture() override = 0;
|
||||||
int Read(int fd, char*buf, int size);
|
int Read(int fd, char*buf, int size);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1069,7 +1069,7 @@ int RemoteCameraHttp::PreCapture() {
|
||||||
return 1;
|
return 1;
|
||||||
} // end int RemoteCameraHttp::PreCapture()
|
} // end int RemoteCameraHttp::PreCapture()
|
||||||
|
|
||||||
int RemoteCameraHttp::Capture(ZMPacket &packet) {
|
int RemoteCameraHttp::Capture(std::shared_ptr<ZMPacket> &packet) {
|
||||||
int content_length = GetResponse();
|
int content_length = GetResponse();
|
||||||
if (content_length == 0) {
|
if (content_length == 0) {
|
||||||
Warning("Unable to capture image, retrying");
|
Warning("Unable to capture image, retrying");
|
||||||
|
@ -1080,15 +1080,15 @@ int RemoteCameraHttp::Capture(ZMPacket &packet) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!packet.image) {
|
if (!packet->image) {
|
||||||
Debug(4, "Allocating image");
|
Debug(4, "Allocating image");
|
||||||
packet.image = new Image(width, height, colours, subpixelorder);
|
packet->image = new Image(width, height, colours, subpixelorder);
|
||||||
}
|
}
|
||||||
Image *image = packet.image;
|
Image *image = packet->image;
|
||||||
packet.keyframe = 1;
|
packet->keyframe = 1;
|
||||||
packet.codec_type = AVMEDIA_TYPE_VIDEO;
|
packet->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||||
packet.packet.stream_index = mVideoStreamId;
|
packet->packet.stream_index = mVideoStreamId;
|
||||||
packet.stream = mVideoStream;
|
packet->stream = mVideoStream;
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case JPEG :
|
case JPEG :
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
int GetResponse();
|
int GetResponse();
|
||||||
int PrimeCapture() override;
|
int PrimeCapture() override;
|
||||||
int PreCapture() override;
|
int PreCapture() override;
|
||||||
int Capture( ZMPacket &p ) override;
|
int Capture(std::shared_ptr<ZMPacket> &p) override;
|
||||||
int PostCapture() override;
|
int PostCapture() override;
|
||||||
int Close() override { Disconnect(); return 0; };
|
int Close() override { Disconnect(); return 0; };
|
||||||
};
|
};
|
||||||
|
|
|
@ -184,9 +184,9 @@ int RemoteCameraNVSocket::PrimeCapture() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) {
|
int RemoteCameraNVSocket::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
if ( SendRequest("GetNextImage\n") < 0 ) {
|
if (SendRequest("GetNextImage\n") < 0) {
|
||||||
Warning( "Unable to capture image, retrying" );
|
Warning("Unable to capture image, retrying");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int bytes_read = Read(sd, buffer, imagesize);
|
int bytes_read = Read(sd, buffer, imagesize);
|
||||||
|
@ -195,17 +195,17 @@ int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint32_t end;
|
uint32_t end;
|
||||||
if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) {
|
if (Read(sd, (char *) &end , sizeof(end)) < 0) {
|
||||||
Warning("Unable to capture image, retrying");
|
Warning("Unable to capture image, retrying");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( end != 0xFFFFFFFF) {
|
if (end != 0xFFFFFFFF) {
|
||||||
Warning("End Bytes Failed\n");
|
Warning("End Bytes Failed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
zm_packet->image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
||||||
zm_packet.keyframe = 1;
|
zm_packet->keyframe = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
int SendRequest(std::string);
|
int SendRequest(std::string);
|
||||||
int GetResponse();
|
int GetResponse();
|
||||||
int PrimeCapture() override;
|
int PrimeCapture() override;
|
||||||
int Capture(ZMPacket &p) override;
|
int Capture(std::shared_ptr<ZMPacket> &p) override;
|
||||||
int PostCapture() override;
|
int PostCapture() override;
|
||||||
int Close() override { return 0; };
|
int Close() override { return 0; };
|
||||||
};
|
};
|
||||||
|
|
|
@ -218,16 +218,16 @@ int RemoteCameraRtsp::PreCapture() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraRtsp::Capture(ZMPacket &zm_packet) {
|
int RemoteCameraRtsp::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
int frameComplete = false;
|
int frameComplete = false;
|
||||||
AVPacket *packet = &zm_packet.packet;
|
AVPacket *packet = &zm_packet->packet;
|
||||||
if ( !zm_packet.image ) {
|
if ( !zm_packet->image ) {
|
||||||
Debug(1, "Allocating image %dx%d %d colours %d", width, height, colours, subpixelorder);
|
Debug(1, "Allocating image %dx%d %d colours %d", width, height, colours, subpixelorder);
|
||||||
zm_packet.image = new Image(width, height, colours, subpixelorder);
|
zm_packet->image = new Image(width, height, colours, subpixelorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while ( !frameComplete ) {
|
while (!frameComplete) {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
if (!rtspThread || rtspThread->IsStopped())
|
if (!rtspThread || rtspThread->IsStopped())
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -254,7 +254,7 @@ int RemoteCameraRtsp::Capture(ZMPacket &zm_packet) {
|
||||||
continue;
|
continue;
|
||||||
} else if ( nalType == 5 ) {
|
} else if ( nalType == 5 ) {
|
||||||
packet->flags |= AV_PKT_FLAG_KEY;
|
packet->flags |= AV_PKT_FLAG_KEY;
|
||||||
zm_packet.keyframe = 1;
|
zm_packet->keyframe = 1;
|
||||||
// IDR
|
// IDR
|
||||||
buffer += lastSps;
|
buffer += lastSps;
|
||||||
buffer += lastPps;
|
buffer += lastPps;
|
||||||
|
@ -275,14 +275,14 @@ int RemoteCameraRtsp::Capture(ZMPacket &zm_packet) {
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
packet->pts = packet->dts = now.tv_sec*1000000+now.tv_usec;
|
packet->pts = packet->dts = now.tv_sec*1000000+now.tv_usec;
|
||||||
|
|
||||||
int bytes_consumed = zm_packet.decode(mVideoCodecContext);
|
int bytes_consumed = zm_packet->decode(mVideoCodecContext);
|
||||||
if ( bytes_consumed < 0 ) {
|
if ( bytes_consumed < 0 ) {
|
||||||
Error("Error while decoding frame %d", frameCount);
|
Error("Error while decoding frame %d", frameCount);
|
||||||
//Hexdump(Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size());
|
//Hexdump(Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size());
|
||||||
}
|
}
|
||||||
buffer -= packet->size;
|
buffer -= packet->size;
|
||||||
if ( bytes_consumed ) {
|
if ( bytes_consumed ) {
|
||||||
zm_dump_video_frame(zm_packet.in_frame, "remote_rtsp_decode");
|
zm_dump_video_frame(zm_packet->in_frame, "remote_rtsp_decode");
|
||||||
if ( ! mVideoStream->
|
if ( ! mVideoStream->
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
codecpar
|
codecpar
|
||||||
|
@ -293,18 +293,18 @@ int RemoteCameraRtsp::Capture(ZMPacket &zm_packet) {
|
||||||
zm_dump_codec(mVideoCodecContext);
|
zm_dump_codec(mVideoCodecContext);
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
zm_dump_codecpar(mVideoStream->codecpar);
|
zm_dump_codecpar(mVideoStream->codecpar);
|
||||||
mVideoStream->codecpar->width = zm_packet.in_frame->width;
|
mVideoStream->codecpar->width = zm_packet->in_frame->width;
|
||||||
mVideoStream->codecpar->height = zm_packet.in_frame->height;
|
mVideoStream->codecpar->height = zm_packet->in_frame->height;
|
||||||
#else
|
#else
|
||||||
mVideoStream->codec->width = zm_packet.in_frame->width;
|
mVideoStream->codec->width = zm_packet->in_frame->width;
|
||||||
mVideoStream->codec->height = zm_packet.in_frame->height;
|
mVideoStream->codec->height = zm_packet->in_frame->height;
|
||||||
#endif
|
#endif
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
zm_dump_codecpar(mVideoStream->codecpar);
|
zm_dump_codecpar(mVideoStream->codecpar);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
zm_packet.codec_type = mVideoCodecContext->codec_type;
|
zm_packet->codec_type = mVideoCodecContext->codec_type;
|
||||||
zm_packet.stream = mVideoStream;
|
zm_packet->stream = mVideoStream;
|
||||||
frameComplete = true;
|
frameComplete = true;
|
||||||
Debug(2, "Frame: %d - %d/%d", frameCount, bytes_consumed, buffer.size());
|
Debug(2, "Frame: %d - %d/%d", frameCount, bytes_consumed, buffer.size());
|
||||||
packet->data = nullptr;
|
packet->data = nullptr;
|
||||||
|
|
|
@ -79,7 +79,7 @@ public:
|
||||||
|
|
||||||
int PrimeCapture() override;
|
int PrimeCapture() override;
|
||||||
int PreCapture() override;
|
int PreCapture() override;
|
||||||
int Capture(ZMPacket &p) override;
|
int Capture(std::shared_ptr <ZMPacket> &p) override;
|
||||||
int PostCapture() override;
|
int PostCapture() override;
|
||||||
int Close() override { return 0; };
|
int Close() override { return 0; };
|
||||||
|
|
||||||
|
|
|
@ -1002,17 +1002,17 @@ bool VideoStore::setup_resampler() {
|
||||||
#endif
|
#endif
|
||||||
} // end bool VideoStore::setup_resampler()
|
} // end bool VideoStore::setup_resampler()
|
||||||
|
|
||||||
int VideoStore::writePacket(ZMPacket *ipkt) {
|
int VideoStore::writePacket(const std::shared_ptr<ZMPacket> &ipkt) {
|
||||||
if ( ipkt->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
if (ipkt->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
return writeVideoFramePacket(ipkt);
|
return writeVideoFramePacket(ipkt);
|
||||||
} else if ( ipkt->codec_type == AVMEDIA_TYPE_AUDIO ) {
|
} else if (ipkt->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||||
return writeAudioFramePacket(ipkt);
|
return writeAudioFramePacket(ipkt);
|
||||||
}
|
}
|
||||||
Error("Unknown stream type in packet (%d)", ipkt->codec_type);
|
Error("Unknown stream type in packet (%d)", ipkt->codec_type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
|
int VideoStore::writeVideoFramePacket(const std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
int ret;
|
int ret;
|
||||||
frame_count += 1;
|
frame_count += 1;
|
||||||
|
|
||||||
|
@ -1056,8 +1056,8 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
|
||||||
swscale.Convert(zm_packet->in_frame, out_frame);
|
swscale.Convert(zm_packet->in_frame, out_frame);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Error("Have neither in_frame or image in packet %p %d!",
|
Error("Have neither in_frame or image in packet %d!",
|
||||||
zm_packet, zm_packet->image_index);
|
zm_packet->image_index);
|
||||||
return 0;
|
return 0;
|
||||||
} // end if has packet or image
|
} // end if has packet or image
|
||||||
} else {
|
} else {
|
||||||
|
@ -1104,13 +1104,13 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
|
||||||
frame->pkt_duration = 0;
|
frame->pkt_duration = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int64_t in_pts = zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec;
|
int64_t in_pts = zm_packet->timestamp.tv_sec * (uint64_t)1000000 + zm_packet->timestamp.tv_usec;
|
||||||
if ( !video_first_pts ) {
|
if ( !video_first_pts ) {
|
||||||
video_first_pts = in_pts;
|
video_first_pts = in_pts;
|
||||||
Debug(2, "No video_first_pts, set to (%" PRId64 ") secs(%" PRIi64 ") usecs(%" PRIi64 ")",
|
Debug(2, "No video_first_pts, set to (%" PRId64 ") secs(%" PRIi64 ") usecs(%" PRIi64 ")",
|
||||||
video_first_pts,
|
video_first_pts,
|
||||||
static_cast<int64>(zm_packet->timestamp->tv_sec),
|
static_cast<int64>(zm_packet->timestamp.tv_sec),
|
||||||
static_cast<int64>(zm_packet->timestamp->tv_usec));
|
static_cast<int64>(zm_packet->timestamp.tv_usec));
|
||||||
frame->pts = 0;
|
frame->pts = 0;
|
||||||
} else {
|
} else {
|
||||||
uint64_t useconds = in_pts - video_first_pts;
|
uint64_t useconds = in_pts - video_first_pts;
|
||||||
|
@ -1121,8 +1121,8 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
|
||||||
frame->pts,
|
frame->pts,
|
||||||
video_first_pts,
|
video_first_pts,
|
||||||
useconds,
|
useconds,
|
||||||
static_cast<int64>(zm_packet->timestamp->tv_sec),
|
static_cast<int64>(zm_packet->timestamp.tv_sec),
|
||||||
static_cast<int64>(zm_packet->timestamp->tv_usec),
|
static_cast<int64>(zm_packet->timestamp.tv_usec),
|
||||||
video_out_ctx->time_base.num,
|
video_out_ctx->time_base.num,
|
||||||
video_out_ctx->time_base.den);
|
video_out_ctx->time_base.den);
|
||||||
}
|
}
|
||||||
|
@ -1228,7 +1228,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
|
||||||
return 1;
|
return 1;
|
||||||
} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
|
} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
|
||||||
|
|
||||||
int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
int VideoStore::writeAudioFramePacket(const std::shared_ptr<ZMPacket> &zm_packet) {
|
||||||
|
|
||||||
AVPacket *ipkt = &zm_packet->packet;
|
AVPacket *ipkt = &zm_packet->packet;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include "zm_ffmpeg.h"
|
#include "zm_ffmpeg.h"
|
||||||
#include "zm_swscale.h"
|
#include "zm_swscale.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#ifdef HAVE_LIBSWRESAMPLE
|
#ifdef HAVE_LIBSWRESAMPLE
|
||||||
#include "libswresample/swresample.h"
|
#include "libswresample/swresample.h"
|
||||||
|
@ -119,9 +121,9 @@ class VideoStore {
|
||||||
|
|
||||||
void write_video_packet(AVPacket &pkt);
|
void write_video_packet(AVPacket &pkt);
|
||||||
void write_audio_packet(AVPacket &pkt);
|
void write_audio_packet(AVPacket &pkt);
|
||||||
int writeVideoFramePacket(ZMPacket *pkt);
|
int writeVideoFramePacket(const std::shared_ptr<ZMPacket> &pkt);
|
||||||
int writeAudioFramePacket(ZMPacket *pkt);
|
int writeAudioFramePacket(const std::shared_ptr<ZMPacket> &pkt);
|
||||||
int writePacket(ZMPacket *pkt);
|
int writePacket(const std::shared_ptr<ZMPacket> &pkt);
|
||||||
int write_packets(PacketQueue &queue);
|
int write_packets(PacketQueue &queue);
|
||||||
void flush_codecs();
|
void flush_codecs();
|
||||||
};
|
};
|
||||||
|
|
|
@ -109,7 +109,7 @@ void Zone::Setup(
|
||||||
} // end Zone::Setup
|
} // end Zone::Setup
|
||||||
|
|
||||||
Zone::~Zone() {
|
Zone::~Zone() {
|
||||||
if ( image )
|
if (image)
|
||||||
delete image;
|
delete image;
|
||||||
delete pg_image;
|
delete pg_image;
|
||||||
delete[] ranges;
|
delete[] ranges;
|
||||||
|
|
|
@ -301,6 +301,7 @@ int main(int argc, char *argv[]) {
|
||||||
result = -1;
|
result = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Debug(1, "Capture:");
|
||||||
if (monitors[i]->Capture() < 0) {
|
if (monitors[i]->Capture() < 0) {
|
||||||
Error("Failed to capture image from monitor %d %s (%zu/%zu)",
|
Error("Failed to capture image from monitor %d %s (%zu/%zu)",
|
||||||
monitors[i]->Id(), monitors[i]->Name(), i + 1, monitors.size());
|
monitors[i]->Id(), monitors[i]->Name(), i + 1, monitors.size());
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 14292374ccf1328f2d5db20897bd06f99ba4d938
|
Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef
|
Loading…
Reference in New Issue