move the input packet into a member of the camera. Fix packet copying in packetqueue. Implement separate start pts and dts for audio and video

This commit is contained in:
Isaac Connor 2016-09-22 10:43:20 -04:00
parent 3dcc1c3697
commit a5b7b6e74f
7 changed files with 133 additions and 128 deletions

View File

@ -146,8 +146,6 @@ int FfmpegCamera::Capture( Image &image )
mReopenThread = 0;
}
AVPacket packet;
int frameComplete = false;
while ( !frameComplete ) {
int avResult = av_read_frame( mFormatContext, &packet );
@ -386,9 +384,6 @@ int FfmpegCamera::OpenFfmpeg() {
}
}
//
Debug ( 1, "Opened codec" );
// Allocate space for the native video frame
@ -563,13 +558,12 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
int frameComplete = false;
while ( !frameComplete ) {
// We are now allocating dynamically because we need to queue these and may go out of scope.
AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
av_init_packet( packet );
Debug(2, "Before av_init_packe");
av_init_packet( &packet );
Debug(5, "Before av_read_frame");
ret = av_read_frame( mFormatContext, packet );
Debug(5, "After av_read_frame (%d)", ret );
Debug(2, "Before av_read_frame");
ret = av_read_frame( mFormatContext, &packet );
Debug(2, "After av_read_frame (%d)", ret );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
if (
@ -582,21 +576,33 @@ Debug(5, "After av_read_frame (%d)", ret );
ReopenFfmpeg();
}
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet->stream_index, ret, errbuf );
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf );
return( -1 );
}
Debug( 4, "Got packet from stream %d dts (%d) pts(%d)", packet->stream_index, packet->dts, packet->pts );
Debug( 3, "Got packet from stream %d dts (%d) pts(%d) key?(%d)", packet.stream_index, packet.dts, packet.pts, packet.flags & AV_PKT_FLAG_KEY );
//av_packet_ref( &packet, &packet );
//Video recording
if ( recording ) {
Debug(3, "recording:");
// The directory we are recording to is no longer tied to the current event.
// Need to re-init the videostore with the correct directory and start recording again
// for efficiency's sake, we should test for keyframe before we test for directory change...
if ( videoStore && (packet->flags & AV_PKT_FLAG_KEY) && (strcmp(oldDirectory, event_file) != 0 ) ) {
if ( videoStore && (packet.flags & AV_PKT_FLAG_KEY) && (strcmp(oldDirectory, event_file) != 0 ) ) {
// don't open new videostore until we're on a key frame..would this require an offset adjustment for the event as a result?...
// if we store our key frame location with the event will that be enough?
Info("Re-starting video storage module");
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
// Also don't know how much it matters for audio.
if ( packet.stream_index == mVideoStreamId ) {
//Write the packet to our video store
int ret = videoStore->writeVideoFramePacket( &packet );
if ( ret < 0 ) { //Less than zero and we skipped a frame
Warning("Error writing last packet to videostore.");
}
} // end if video
delete videoStore;
videoStore = NULL;
}
@ -637,11 +643,11 @@ Debug(5, "After av_read_frame (%d)", ret );
while ( ( queued_packet = packetqueue.popPacket() ) ) {
packet_count += 1;
//Write the packet to our video store
Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", queued_packet->stream_index, packet->flags & AV_PKT_FLAG_KEY, packetqueue.size() );
Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", queued_packet->stream_index, queued_packet->flags & AV_PKT_FLAG_KEY, packetqueue.size() );
if ( queued_packet->stream_index == mVideoStreamId ) {
ret = videoStore->writeVideoFramePacket( queued_packet, mFormatContext->streams[mVideoStreamId]);
ret = videoStore->writeVideoFramePacket( queued_packet );
} else if ( queued_packet->stream_index == mAudioStreamId ) {
ret = videoStore->writeAudioFramePacket( queued_packet, mFormatContext->streams[mAudioStreamId]);
ret = videoStore->writeAudioFramePacket( queued_packet );
} else {
Warning("Unknown stream id in queued packet (%d)", queued_packet->stream_index );
ret = -1;
@ -663,27 +669,32 @@ Debug(5, "After av_read_frame (%d)", ret );
videoStore = NULL;
}
//Buffer video packets, since we are not recording
if ( (packet->stream_index == mVideoStreamId) && ( packet->flags & AV_PKT_FLAG_KEY ) ) {
//Buffer video packets, since we are not recording. All audio packets are keyframes, so only if it's a video keyframe
if ( (packet.stream_index == mVideoStreamId) && ( packet.flags & AV_PKT_FLAG_KEY ) ) {
Debug(3, "Clearing queue");
packetqueue.clearQueue();
}
packetqueue.queuePacket(packet);
} // end if
if ( packet.stream_index != mAudioStreamId || record_audio ) {
Debug(3, "Queuing");
packetqueue.queuePacket( &packet );
}
} // end if recording or not
if ( packet->stream_index == mVideoStreamId ) {
if ( packet.stream_index == mVideoStreamId ) {
if ( videoStore ) {
//Write the packet to our video store
int ret = videoStore->writeVideoFramePacket( packet, mFormatContext->streams[mVideoStreamId] );
int ret = videoStore->writeVideoFramePacket( &packet );
if ( ret < 0 ) { //Less than zero and we skipped a frame
zm_av_unref_packet( packet );
zm_av_unref_packet( &packet );
return 0;
}
}
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, packet );
Debug(3, "about to decode video" );
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf );
zm_av_unref_packet( packet );
zm_av_unref_packet( &packet );
continue;
}
@ -698,7 +709,7 @@ Debug(5, "After av_read_frame (%d)", ret );
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
if ( directbuffer == NULL ) {
Error("Failed requesting writeable buffer for the captured image.");
zm_av_unref_packet( packet );
zm_av_unref_packet( &packet );
return (-1);
}
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
@ -727,16 +738,16 @@ Debug(5, "After av_read_frame (%d)", ret );
} else {
Debug( 3, "Not framecomplete after av_read_frame" );
} // end if frameComplete
} else if ( packet->stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams
Debug( 4, "Audio stream index %d", packet->stream_index );
} else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams
if ( videoStore ) {
if ( record_audio ) {
Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet->stream_index );
Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet.stream_index );
//Write the packet to our video store
//FIXME no relevance of last key frame
int ret = videoStore->writeAudioFramePacket( packet, mFormatContext->streams[packet->stream_index] );
int ret = videoStore->writeAudioFramePacket( &packet );
if ( ret < 0 ) {//Less than zero and we skipped a frame
zm_av_unref_packet( packet );
Warning("Failure to write audio packet.");
zm_av_unref_packet( &packet );
return 0;
}
} else {
@ -745,15 +756,16 @@ Debug(5, "After av_read_frame (%d)", ret );
}
} else {
#if LIBAVUTIL_VERSION_CHECK(54, 23, 0, 23, 0)
Debug( 3, "Some other stream index %d, %s", packet->stream_index, av_get_media_type_string( mFormatContext->streams[packet->stream_index]->codec->codec_type) );
Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codec->codec_type) );
#else
Debug( 3, "Some other stream index %d", packet->stream_index );
Debug( 3, "Some other stream index %d", packet.stream_index );
#endif
}
if ( videoStore ) {
zm_av_unref_packet( packet );
av_free( packet );
}
//if ( videoStore ) {
// the packet contents are ref counted... when queuing, we allocate another packet and reference it with that one, so we should always need to unref here, which should not affect the queued version.
zm_av_unref_packet( &packet );
//}
} // end while ! frameComplete
return (frameCount);
}

View File

@ -36,8 +36,8 @@ class FfmpegCamera : public Camera
{
protected:
std::string mPath;
std::string mMethod;
std::string mOptions;
std::string mMethod;
std::string mOptions;
int frameCount;
@ -51,7 +51,12 @@ class FfmpegCamera : public Camera
AVCodec *mAudioCodec;
AVFrame *mRawFrame;
AVFrame *mFrame;
_AVPIXELFORMAT imagePixFormat;
_AVPIXELFORMAT imagePixFormat;
// Used to store the incoming packet, it will get copied when queued.
// We only ever need one at a time, so instead of constantly allocating
// and freeing this structure, we will just make it a member of the object.
AVPacket packet;
int OpenFfmpeg();
int ReopenFfmpeg();
@ -67,10 +72,8 @@ class FfmpegCamera : public Camera
bool wasRecording;
VideoStore *videoStore;
char oldDirectory[4096];
zm_packetqueue packetqueue;
// Last Key frame
//AVPacket lastKeyframePkt;
unsigned int old_event_id;
zm_packetqueue packetqueue;
#if HAVE_LIBSWSCALE
struct SwsContext *mConvertContext;

View File

@ -35,17 +35,18 @@ zm_packetqueue::~zm_packetqueue() {
bool zm_packetqueue::queuePacket( AVPacket* packet ) {
//AVPacket *input_ref = (AVPacket *)av_malloc(sizeof(AVPacket));
//if ( av_packet_ref( input_ref, packet ) < 0 ) {
if ( 0 ) {
if ( av_packet_ref( packet, packet ) < 0 ) {
AVPacket *input_ref = (AVPacket *)av_malloc(sizeof(AVPacket));
av_init_packet( input_ref );
if ( av_packet_ref( input_ref, packet ) < 0 ) {
Error("error refing packet");
//av_free_packet(input_ref);
av_free(input_ref);
return false;
}
} else {
Debug(3, "made a ref");
}
pktQueue.push( packet );
pktQueue.push( input_ref );
Debug(3, "queued");
//pktQueue.push( input_ref );
return true;

View File

@ -523,7 +523,7 @@ int RemoteCameraRtsp::CaptureAndRecord(Image &image, bool recording, char* event
if ( videoStore ) {
//Write the packet to our video store
int ret = videoStore->writeVideoFramePacket(&packet, mFormatContext->streams[mVideoStreamId]);//, &lastKeyframePkt);
int ret = videoStore->writeVideoFramePacket(&packet);//, &lastKeyframePkt);
if ( ret < 0 ) {//Less than zero and we skipped a frame
// Should not
av_free_packet( &packet );
@ -553,7 +553,7 @@ int RemoteCameraRtsp::CaptureAndRecord(Image &image, bool recording, char* event
if ( videoStore && record_audio ) {
Debug( 4, "Storing Audio packet" );
//Write the packet to our video store
int ret = videoStore->writeAudioFramePacket(&packet, mFormatContext->streams[packet.stream_index]); //FIXME no relevance of last key frame
int ret = videoStore->writeAudioFramePacket( &packet ); //FIXME no relevance of last key frame
if ( ret < 0 ) { //Less than zero and we skipped a frame
#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100)
av_packet_unref( &packet );

View File

@ -33,11 +33,13 @@ extern "C"{
}
VideoStore::VideoStore(const char *filename_in, const char *format_in,
AVStream *input_video_stream,
AVStream *input_audio_stream,
AVStream *p_input_video_stream,
AVStream *p_input_audio_stream,
int64_t nStartTime,
Monitor::Orientation orientation
) {
input_video_stream = p_input_video_stream;
input_audio_stream = p_input_audio_stream;
//store inputs in variables local to class
filename = filename_in;
@ -296,13 +298,16 @@ Debug(2, "Have audio_output_context");
}
prevDts = 0;
startPts = 0;
startDts = 0;
video_start_pts = 0;
video_start_dts = 0;
audio_start_pts = 0;
audio_start_dts = 0;
filter_in_rescale_delta_last = AV_NOPTS_VALUE;
// now - when streaming started
startTime=av_gettime()-nStartTime;//oc->start_time;
Info("VideoStore startTime=%d\n",startTime);
//startTime=av_gettime()-nStartTime;//oc->start_time;
//Info("VideoStore startTime=%d\n",startTime);
} // VideoStore::VideoStore
@ -355,7 +360,7 @@ void VideoStore::dumpPacket( AVPacket *pkt ){
Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b);
}
int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_video_stream){
int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) {
AVPacket opkt;
AVPicture pict;
@ -366,13 +371,13 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_video_stre
if ( 1 ) {
//Scale the PTS of the outgoing packet to be the correct time base
if (ipkt->pts != AV_NOPTS_VALUE) {
if ( ! startPts ) {
if ( ! video_start_pts ) {
//never gets set, so the first packet can set it.
startPts = ipkt->pts;
video_start_pts = ipkt->pts;
}
opkt.pts = av_rescale_q(ipkt->pts-startPts, input_video_stream->time_base, video_stream->time_base);
opkt.pts = av_rescale_q(ipkt->pts - video_start_pts, input_video_stream->time_base, video_stream->time_base);
//- ost_tb_start_time;
Debug(3, "opkt.pts = %d from ipkt->pts(%d) - startPts(%d)", opkt.pts, ipkt->pts, startPts );
Debug(3, "opkt.pts = %d from ipkt->pts(%d) - startPts(%d)", opkt.pts, ipkt->pts, video_start_pts );
} else {
Debug(3, "opkt.pts = undef");
opkt.pts = AV_NOPTS_VALUE;
@ -380,23 +385,22 @@ if ( 1 ) {
//Scale the DTS of the outgoing packet to be the correct time base
if(ipkt->dts == AV_NOPTS_VALUE) {
if ( ! startDts ) startDts = input_video_stream->cur_dts;
opkt.dts = av_rescale_q(input_video_stream->cur_dts-startDts, AV_TIME_BASE_Q, video_stream->time_base);
// why are we using cur_dts instead of packet.dts?
if ( ! video_start_dts ) video_start_dts = input_video_stream->cur_dts;
opkt.dts = av_rescale_q(input_video_stream->cur_dts - video_start_dts, AV_TIME_BASE_Q, video_stream->time_base);
Debug(3, "opkt.dts = %d from input_video_stream->cur_dts(%d) - startDts(%d)",
opkt.dts, input_video_stream->cur_dts, startDts
opkt.dts, input_video_stream->cur_dts, video_start_dts
);
} else {
if ( ! startDts ) startDts = ipkt->dts;
opkt.dts = av_rescale_q(ipkt->dts - startDts, input_video_stream->time_base, video_stream->time_base);
Debug(3, "opkt.dts = %d from ipkt->dts(%d) - startDts(%d)", opkt.dts, ipkt->dts, startDts );
if ( ! video_start_dts ) video_start_dts = ipkt->dts;
opkt.dts = av_rescale_q(ipkt->dts - video_start_dts, input_video_stream->time_base, video_stream->time_base);
Debug(3, "opkt.dts = %d from ipkt->dts(%d) - startDts(%d)", opkt.dts, ipkt->dts, video_start_dts );
}
if ( opkt.dts > opkt.pts ) {
Warning("opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts );
Debug( 1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts );
opkt.dts = opkt.pts;
}
//opkt.dts -= ost_tb_start_time;
opkt.duration = av_rescale_q(ipkt->duration, input_video_stream->time_base, video_stream->time_base);
} else {
av_packet_rescale_ts( &opkt, input_video_stream->time_base, video_stream->time_base );
@ -459,8 +463,8 @@ Debug(4, "Not video and RAWPICTURE");
}
int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_audio_stream){
Debug(2, "writeAudioFrame");
int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
Debug(4, "writeAudioFrame");
if(!audio_stream) {
Error("Called writeAudioFramePacket when no audio_stream");
@ -471,61 +475,50 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_audio_stre
//zm_dump_stream_format( oc, ipkt->stream_index, 0, 1 );
int ret;
// What is this doing? Getting the time of the start of this video chunk? Does that actually make sense?
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, audio_stream->time_base);
AVPacket opkt;
av_init_packet(&opkt);
Debug(3, "after init packet" );
//Scale the PTS of the outgoing packet to be the correct time base
//Scale the PTS of the outgoing packet to be the correct time base
if (ipkt->pts != AV_NOPTS_VALUE) {
Debug(2, "Rescaling output pts");
opkt.pts = av_rescale_q(ipkt->pts-startPts, input_audio_stream->time_base, audio_stream->time_base) - ost_tb_start_time;
if ( ! audio_start_pts ) {
//never gets set, so the first packet can set it.
audio_start_pts = ipkt->pts;
}
opkt.pts = av_rescale_q(ipkt->pts-audio_start_pts, input_audio_stream->time_base, audio_stream->time_base);
Debug(3, "opkt.pts = %d from ipkt->pts(%d) - startPts(%d)", opkt.pts, ipkt->pts, audio_start_pts );
} else {
Debug(2, "Setting output pts to AV_NOPTS_VALUE");
Debug(3, "opkt.pts = undef");
opkt.pts = AV_NOPTS_VALUE;
}
//Scale the DTS of the outgoing packet to be the correct time base
if(ipkt->dts == AV_NOPTS_VALUE) {
Debug(2, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
opkt.dts = av_rescale_q(input_audio_stream->cur_dts-startDts, AV_TIME_BASE_Q, audio_stream->time_base);
Debug(2, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
if ( ! audio_start_dts ) audio_start_dts = input_video_stream->cur_dts;
opkt.dts = av_rescale_q(input_video_stream->cur_dts - audio_start_dts, AV_TIME_BASE_Q, audio_stream->time_base);
Debug(3, "opkt.dts = %d from input_video_stream->cur_dts(%d) - startDts(%d)",
opkt.dts, input_audio_stream->cur_dts, audio_start_dts
);
} else {
Debug(2, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
opkt.dts = av_rescale_q(ipkt->dts-startDts, input_audio_stream->time_base, audio_stream->time_base);
Debug(2, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
if ( ! audio_start_dts ) audio_start_dts = ipkt->dts;
opkt.dts = av_rescale_q(ipkt->dts - audio_start_dts, input_audio_stream->time_base, audio_stream->time_base);
Debug(3, "opkt.dts = %d from ipkt->dts(%d) - startDts(%d)", opkt.dts, ipkt->dts, audio_start_dts );
}
Debug(2, "Not sure what ost_tb_start_time is (%d) - (%d)", opkt.dts, ost_tb_start_time );
opkt.dts -= ost_tb_start_time;
// Seems like it would be really weird for the codec type to NOT be audiu
if (audio_stream->codec->codec_type == AVMEDIA_TYPE_AUDIO && ipkt->dts != AV_NOPTS_VALUE) {
int duration = av_get_audio_frame_duration(input_audio_stream->codec, ipkt->size);
Debug( 1, "code is audio, dts != AV_NOPTS_VALUE got duration(%d)", duration );
if ( ! duration ) {
duration = input_audio_stream->codec->frame_size;
Warning( "got no duration from av_get_audio_frame_duration. Using frame size(%d)", duration );
}
//FIXME where to get filter_in_rescale_delta_last
//FIXME av_rescale_delta doesn't exist in ubuntu vivid libavtools
opkt.dts = opkt.pts = av_rescale_delta(input_audio_stream->time_base, ipkt->dts,
(AVRational){1, input_audio_stream->codec->sample_rate}, duration, &filter_in_rescale_delta_last,
audio_stream->time_base) - ost_tb_start_time;
Debug(2, "rescaled dts is: (%d)", opkt.dts );
if ( opkt.dts > opkt.pts ) {
Debug(1,"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts );
opkt.dts = opkt.pts;
}
opkt.duration = av_rescale_q(ipkt->duration, input_audio_stream->time_base, audio_stream->time_base);
opkt.pos=-1;
// pkt.pos: byte position in stream, -1 if unknown
opkt.pos = -1;
opkt.flags = ipkt->flags;
opkt.stream_index = ipkt->stream_index;
if ( audio_output_codec ) {
// we are transcoding
AVFrame *input_frame;
AVFrame *output_frame;

View File

@ -15,6 +15,9 @@ private:
AVStream *video_stream;
AVStream *audio_stream;
AVStream *input_video_stream;
AVStream *input_audio_stream;
// The following are used when encoding the audio stream to AAC
AVCodec *audio_output_codec;
AVCodecContext *audio_output_context;
@ -26,9 +29,11 @@ private:
bool keyframeMessage;
int keyframeSkipNumber;
int64_t startTime;
int64_t startPts;
int64_t startDts;
int64_t video_start_pts;
int64_t video_start_dts;
int64_t audio_start_pts;
int64_t audio_start_dts;
int64_t prevDts;
int64_t filter_in_rescale_delta_last;
@ -36,23 +41,11 @@ public:
VideoStore(const char *filename_in, const char *format_in, AVStream *input_video_stream, AVStream *input_audio_stream, int64_t nStartTime, Monitor::Orientation p_orientation );
~VideoStore();
int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt);
int writeAudioFramePacket(AVPacket *pkt, AVStream *input_st);
int writeVideoFramePacket( AVPacket *pkt );
int writeAudioFramePacket( AVPacket *pkt );
void dumpPacket( AVPacket *pkt );
};
/*
class VideoEvent {
public:
VideoEvent(unsigned int eid);
~VideoEvent();
int createEventImage(unsigned int fid, char *&pBuff);
private:
unsigned int m_eid;
};*/
#endif //havelibav
#endif //zm_videostore_h

View File

@ -48,7 +48,10 @@ void Zone::Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_
overload_frames = p_overload_frames;
extend_alarm_frames = p_extend_alarm_frames;
Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames );
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames );
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames );
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method );
Debug( 1, "Initialised zone %d/%s - %d - %dx%d", id, label, type, polygon.Width(), polygon.Height() );
alarmed = false;
pixel_diff = 0;