From 9a795432cfafcf235a23974112536717805d5df2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 5 Apr 2016 17:14:46 -0400 Subject: [PATCH] merge all the commits from the messed up iconnor_video branch --- CMakeLists.txt | 2 +- README.md | 2 +- db/zm_create.sql.in | 5 + distros/ubuntu1504_cmake/changelog | 6 + distros/ubuntu1504_cmake/control | 2 + src/zm_camera.cpp | 5 +- src/zm_camera.h | 7 +- src/zm_curl_camera.cpp | 5 +- src/zm_curl_camera.h | 2 +- src/zm_event.cpp | 0 src/zm_event.h | 0 src/zm_ffmpeg_camera.cpp | 138 +- src/zm_ffmpeg_camera.h | 4 +- src/zm_file_camera.cpp | 2 +- src/zm_file_camera.h | 4 +- src/zm_libvlc_camera.cpp | 4 +- src/zm_libvlc_camera.h | 4 +- src/zm_local_camera.cpp | 22 +- src/zm_local_camera.h | 22 +- src/zm_monitor.cpp | 7462 +++++++++++++-------------- src/zm_monitor.h | 332 +- src/zm_remote_camera.cpp | 19 +- src/zm_remote_camera.h | 19 +- src/zm_remote_camera_http.cpp | 4 +- src/zm_remote_camera_http.h | 4 +- src/zm_remote_camera_rtsp.cpp | 556 +- src/zm_remote_camera_rtsp.h | 20 +- src/zm_rtp_source.cpp | 17 +- src/zm_video.cpp | 2 +- src/zm_video.h | 4 +- src/zm_videostore.cpp | 0 src/zm_videostore.h | 0 version | 2 +- web/api/.gitattributes | 33 - web/api/.gitignore | 21 - web/includes/functions.php | 34 +- web/lang/en_gb.php | 1 + web/skins/classic/views/event.php | 2 +- web/skins/classic/views/monitor.php | 3 + 39 files changed, 4487 insertions(+), 4284 deletions(-) mode change 100755 => 100644 src/zm_camera.h mode change 100755 => 100644 src/zm_event.cpp mode change 100755 => 100644 src/zm_event.h mode change 100755 => 100644 src/zm_ffmpeg_camera.cpp mode change 100755 => 100644 src/zm_ffmpeg_camera.h mode change 100755 => 100644 src/zm_monitor.cpp mode change 100755 => 100644 src/zm_videostore.cpp mode change 100755 => 100644 src/zm_videostore.h delete mode 100644 web/api/.gitattributes delete mode 100644 web/api/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index ca611a358..92931618d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # cmake_minimum_required (VERSION 2.6) project (zoneminder) -set(zoneminder_VERSION "1.29.0") +set(zoneminder_VERSION "1.30.0") # make API version a minor of ZM version set(zoneminder_API_VERSION "${zoneminder_VERSION}.1") diff --git a/README.md b/README.md index c0d9c2fd1..f6c4c084b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ZoneMinder H264 Patch [![Build Status](https://travis-ci.org/ZoneMinder/ZoneMinder.png?branch=feature-h264-videostorage)](https://travis-ci.org/ZoneMinder/ZoneMinder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received) ##Feature-h264-videostorage Branch Details -This branch supports direct recording of h264 cameras into MP4 format uisng the h264 Passthrough option, but only with FFMPEG Monitors currently. It also it provides h264 encoding from jpegs of any other monitor type and local or mpeg cameras. If you encounter any issues, please open an issue on GitHub and attach it to the h264 milestone. But do remember this is bleeding edge so it will have problems. +This branch supports direct recording of h264 cameras into MP4 format uisng the h264 Passthrough option. As well it provides h264 encoding for local or mpeg cameras. If you encounter any issues, please open an issue on GitHub and attach it to the h264 milestone. But do remember this is bleeding edge so it will have problems. Thanks to @chriswiggins and @mastertheknife for their work, @SteveGilvarry is now maintaining this branch and welcomes any assistance. **The following SQL changes are required, these will be merged to zmupdate once we are ready to merge this branch to master.** diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 029f20989..3a3a96691 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -193,6 +193,7 @@ CREATE TABLE `Events` ( `Length` decimal(10,2) NOT NULL default '0.00', `Frames` int(10) unsigned default NULL, `AlarmFrames` int(10) unsigned default NULL, + `DefaultVideo` VARCHAR( 64 ) NOT NULL, `TotScore` int(10) unsigned NOT NULL default '0', `AvgScore` smallint(5) unsigned default '0', `MaxScore` smallint(5) unsigned default '0', @@ -344,6 +345,10 @@ CREATE TABLE `Monitors` ( `Palette` int(10) unsigned NOT NULL default '0', `Orientation` enum('0','90','180','270','hori','vert') NOT NULL default '0', `Deinterlacing` int(10) unsigned NOT NULL default '0', + `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' , + `VideoWriter` TINYINT NOT NULL DEFAULT '0', + `EncoderParameters` TEXT NOT NULL, + `RecordAudio` TINYINT NOT NULL DEFAULT '0', `RTSPDescribe` tinyint(1) unsigned NOT NULL default '0', `Brightness` mediumint(7) NOT NULL default '-1', `Contrast` mediumint(7) NOT NULL default '-1', diff --git a/distros/ubuntu1504_cmake/changelog b/distros/ubuntu1504_cmake/changelog index 74cf1d0b8..cba330237 100644 --- a/distros/ubuntu1504_cmake/changelog +++ b/distros/ubuntu1504_cmake/changelog @@ -1,3 +1,9 @@ +zoneminder (1.29.0+h264-wily-SNAPSHOT2016033101) wily; urgency=medium + + * + + -- Isaac Connor Thu, 31 Mar 2016 10:29:41 -0400 + zoneminder (1.28.1+1-vivid-SNAPSHOT2015081701) vivid; urgency=medium * include api, switch to cmake build diff --git a/distros/ubuntu1504_cmake/control b/distros/ubuntu1504_cmake/control index 50dee74c6..2c7106fde 100644 --- a/distros/ubuntu1504_cmake/control +++ b/distros/ubuntu1504_cmake/control @@ -21,6 +21,7 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa ,libphp-serialization-perl ,libsys-mmap-perl [!hurd-any] ,libwww-perl + ,libx264-dev, libmp4v2-dev # Unbundled (dh_linktree): ,libjs-jquery ,libjs-mootools @@ -61,6 +62,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,policykit-1 ,rsyslog | system-log-daemon ,zip + ,libmp4v2-2 Recommends: ${misc:Recommends} ,libapache2-mod-php5 | php5-fpm ,mysql-server | virtual-mysql-server diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index 18950d341..f8c9fd6af 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -20,7 +20,7 @@ #include "zm.h" #include "zm_camera.h" -Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : +Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : id( p_id ), type( p_type ), width( p_width), @@ -31,7 +31,8 @@ Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_co hue( p_hue ), colour( p_colour ), contrast( p_contrast ), - capture( p_capture ) + capture( p_capture ), + record_audio( p_record_audio ) { pixels = width * height; imagesize = pixels * colours; diff --git a/src/zm_camera.h b/src/zm_camera.h old mode 100755 new mode 100644 index 5d54919f1..eb161b9f0 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -47,9 +47,10 @@ protected: int colour; int contrast; bool capture; + bool record_audio; public: - Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); virtual ~Camera(); int getId() const { return( id ); } @@ -74,13 +75,13 @@ public: bool CanCapture() const { return( capture ); } - bool SupportsNativeVideo() const { return( type == FFMPEG_SRC ); } + bool SupportsNativeVideo() const { return( (type == FFMPEG_SRC )||(type == REMOTE_SRC)); } virtual int PrimeCapture() { return( 0 ); } virtual int PreCapture()=0; virtual int Capture( Image &image )=0; virtual int PostCapture()=0; - virtual int CaptureAndRecord( Image &image, bool recording, char* event_directory)=0; + virtual int CaptureAndRecord( Image &image, bool recording, char* event_directory)=0; }; #endif // ZM_CAMERA_H diff --git a/src/zm_curl_camera.cpp b/src/zm_curl_camera.cpp index 44786a527..303b53528 100644 --- a/src/zm_curl_camera.cpp +++ b/src/zm_curl_camera.cpp @@ -30,8 +30,8 @@ const char* content_type_match = "Content-Type:"; size_t content_length_match_len; size_t content_type_match_len; -cURLCamera::cURLCamera( int p_id, const std::string &p_path, const std::string &p_user, const std::string &p_pass, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : - Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ), +cURLCamera::cURLCamera( int p_id, const std::string &p_path, const std::string &p_user, const std::string &p_pass, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : + Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), mPath( p_path ), mUser( p_user ), mPass ( p_pass ), bTerminate( false ), bReset( false ), mode ( MODE_UNSET ) { @@ -313,6 +313,7 @@ int cURLCamera::PostCapture() int cURLCamera::CaptureAndRecord( Image &image, bool recording, char* event_directory ) { + Error("Capture and Record not implemented for the cURL camera type"); // Nothing to do here return( 0 ); } diff --git a/src/zm_curl_camera.h b/src/zm_curl_camera.h index a05d536ba..dcf39f94a 100644 --- a/src/zm_curl_camera.h +++ b/src/zm_curl_camera.h @@ -65,7 +65,7 @@ protected: pthread_cond_t request_complete_cond; public: - cURLCamera( int p_id, const std::string &path, const std::string &username, const std::string &password, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + cURLCamera( int p_id, const std::string &path, const std::string &username, const std::string &password, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~cURLCamera(); const std::string &Path() const { return( mPath ); } diff --git a/src/zm_event.cpp b/src/zm_event.cpp old mode 100755 new mode 100644 diff --git a/src/zm_event.h b/src/zm_event.h old mode 100755 new mode 100644 diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp old mode 100755 new mode 100644 index add6328f4..653f82b65 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -36,8 +36,8 @@ extern "C"{ #include #endif -FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : - Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ), +FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : + Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), mPath( p_path ), mMethod( p_method ), mOptions( p_options ) @@ -168,7 +168,7 @@ int FfmpegCamera::Capture( Image &image ) (avResult == -110) ) { - Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf); + Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf ); ReopenFfmpeg(); } @@ -176,6 +176,7 @@ int FfmpegCamera::Capture( Image &image ) return( -1 ); } Debug( 5, "Got packet from stream %d", packet.stream_index ); + // What about audio stream? Maybe someday we could do sound detection... if ( packet.stream_index == mVideoStreamId ) { #if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) @@ -187,37 +188,38 @@ int FfmpegCamera::Capture( Image &image ) Debug( 4, "Decoded video packet at frame %d", frameCount ); - if ( frameComplete ) - { + if ( frameComplete ) { Debug( 3, "Got frame %d", frameCount ); - avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); + avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); #if HAVE_LIBSWSCALE - if(mConvertContext == NULL) { - mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); + if(mConvertContext == NULL) { + mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); - if(mConvertContext == NULL) - Fatal( "Unable to create conversion context for %s", mPath.c_str() ); - } + if(mConvertContext == NULL) + Fatal( "Unable to create conversion context for %s", mPath.c_str() ); + } - if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 ) - Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount ); + if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 ) + Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount ); #else // HAVE_LIBSWSCALE - Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" ); + Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" ); #endif // HAVE_LIBSWSCALE - + frameCount++; - } - } + } // end if frameComplete + } else { + Debug( 4, "Different stream_index %d", packet.stream_index ); + } // end if packet.stream_index == mVideoStreamId #if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100) av_packet_unref( &packet); #else av_free_packet( &packet ); #endif - } + } // end while ! frameComplete return (0); -} +} // FfmpegCamera::Capture int FfmpegCamera::PostCapture() { @@ -312,6 +314,7 @@ int FfmpegCamera::OpenFfmpeg() { // Find first video stream present mVideoStreamId = -1; + mAudioStreamId = -1; for (unsigned int i=0; i < mFormatContext->nb_streams; i++ ) { #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) @@ -320,23 +323,32 @@ int FfmpegCamera::OpenFfmpeg() { if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) #endif { - mVideoStreamId = i; - break; + if ( mVideoStreamId == -1 ) { + mVideoStreamId = i; + // if we break, then we won't find the audio stream + continue; + } else { + Debug(2, "Have another video stream." ); + } } - if(mAudioStreamId == -1) //FIXME best way to copy all other streams? - { #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) - if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) + if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) #else - if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) + if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) #endif - { + { + if ( mAudioStreamId == -1 ) { mAudioStreamId = i; - } + } else { + Debug(2, "Have another audio stream." ); + } + } } if ( mVideoStreamId == -1 ) Fatal( "Unable to locate video stream in %s", mPath.c_str() ); + if ( mAudioStreamId == -1 ) + Debug( 3, "Unable to locate audio stream in %s", mPath.c_str() ); Debug ( 1, "Found video stream" ); @@ -521,17 +533,15 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi /* Request a writeable buffer of the target image */ directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - if(directbuffer == NULL) { + if( directbuffer == NULL ) { Error("Failed requesting writeable buffer for the captured image."); return (-1); } int frameComplete = false; - while ( !frameComplete ) - { + while ( !frameComplete ) { int avResult = av_read_frame( mFormatContext, &packet ); - if ( avResult < 0 ) - { + if ( avResult < 0 ) { char errbuf[AV_ERROR_MAX_STRING_SIZE]; av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE); if ( @@ -539,8 +549,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi (avResult == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) || // Check for Connection failure. (avResult == -110) - ) - { + ) { Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf); ReopenFfmpeg(); } @@ -549,8 +558,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi return( -1 ); } Debug( 5, "Got packet from stream %d", packet.stream_index ); - if ( packet.stream_index == mVideoStreamId ) - { + if ( packet.stream_index == mVideoStreamId ) { #if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 ) #else @@ -560,8 +568,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi Debug( 4, "Decoded video packet at frame %d", frameCount ); - if ( frameComplete ) - { + if ( frameComplete ) { Debug( 3, "Got frame %d", frameCount ); avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); @@ -572,21 +579,23 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi //TODO I think we need to store the key frame location for seeking as part of the event //Video recording - if(recording && !wasRecording){ + if ( recording && !wasRecording ) { //Instantiate the video storage module videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime); wasRecording = true; strcpy(oldDirectory, event_file); - }else if(!recording && wasRecording && videoStore){ + } else if ( ( ! recording ) && wasRecording && videoStore ) { Info("Deleting videoStore instance"); delete videoStore; videoStore = NULL; } //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 - if(recording && wasRecording && (strcmp(oldDirectory, event_file)!=0) && (packet.flags & AV_PKT_FLAG_KEY) ){ //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? + if ( recording && wasRecording && (strcmp(oldDirectory, event_file) != 0 ) && (packet.flags & AV_PKT_FLAG_KEY) ) { + // 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"); if(videoStore){ delete videoStore; @@ -597,7 +606,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi strcpy(oldDirectory, event_file); } - if(videoStore && recording){ + if ( videoStore && recording ) { //Write the packet to our video store int ret = videoStore->writeVideoFramePacket(&packet, mFormatContext->streams[mVideoStreamId]);//, &lastKeyframePkt); if(ret<0){//Less than zero and we skipped a frame @@ -607,32 +616,37 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi } #if HAVE_LIBSWSCALE - if(mConvertContext == NULL) { - mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); - if(mConvertContext == NULL) - Fatal( "Unable to create conversion context for %s", mPath.c_str() ); - } + if ( mConvertContext == NULL ) { + mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); + if ( mConvertContext == NULL ) + Fatal( "Unable to create conversion context for %s", mPath.c_str() ); + } - if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 ) - Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount ); + if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 ) + Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount ); #else // HAVE_LIBSWSCALE - Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" ); + Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" ); #endif // HAVE_LIBSWSCALE - - frameCount++; - } - }else if(packet.stream_index == mAudioStreamId){//FIXME best way to copy all other streams - if(videoStore && recording){ - //Write the packet to our video store - int ret = videoStore->writeAudioFramePacket(&packet, mFormatContext->streams[packet.stream_index]); //FIXME no relevance of last key frame - if(ret<0){//Less than zero and we skipped a frame - av_free_packet( &packet ); - return 0; - } + + frameCount++; + } // end if frameComplete + } else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams + if ( videoStore && recording ) { + if ( record_audio ) { + Debug(4, "Recording 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 + if ( ret < 0 ) {//Less than zero and we skipped a frame + av_free_packet( &packet ); + return 0; + } + } else { + Debug(4, "Not recording audio packet" ); + } } } av_free_packet( &packet ); - } + } // end while ! frameComplete return (frameCount); } diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h old mode 100755 new mode 100644 index 46aa40210..bc7ec2ecb --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -73,7 +73,7 @@ protected: int64_t startTime; public: - FfmpegCamera( int p_id, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + FfmpegCamera( int p_id, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~FfmpegCamera(); const std::string &Path() const { return( mPath ); } @@ -86,7 +86,7 @@ public: int PrimeCapture(); int PreCapture(); int Capture( Image &image ); - int CaptureAndRecord( Image &image, bool recording, char* event_directory ); + int CaptureAndRecord( Image &image, bool recording, char* event_directory ); int PostCapture(); }; diff --git a/src/zm_file_camera.cpp b/src/zm_file_camera.cpp index 28ce2b155..f9ec73b26 100644 --- a/src/zm_file_camera.cpp +++ b/src/zm_file_camera.cpp @@ -34,7 +34,7 @@ #include "zm.h" #include "zm_file_camera.h" -FileCamera::FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : Camera( p_id, FILE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ) +FileCamera::FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : Camera( p_id, FILE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ) { strncpy( path, p_path, sizeof(path) ); if ( capture ) diff --git a/src/zm_file_camera.h b/src/zm_file_camera.h index 98db69b22..a2ed23077 100644 --- a/src/zm_file_camera.h +++ b/src/zm_file_camera.h @@ -36,7 +36,7 @@ protected: char path[PATH_MAX]; public: - FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~FileCamera(); const char *Path() const { return( path ); } @@ -46,7 +46,7 @@ public: int PreCapture(); int Capture( Image &image ); int PostCapture(); - int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; + int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; }; #endif // ZM_FILE_CAMERA_H diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index 1f756f6e0..affd91011 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -61,8 +61,8 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) } } -LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : - Camera( p_id, LIBVLC_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ), +LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : + Camera( p_id, LIBVLC_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), mPath( p_path ), mMethod( p_method ), mOptions( p_options ) diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h index 38e258c11..8c466b5ae 100644 --- a/src/zm_libvlc_camera.h +++ b/src/zm_libvlc_camera.h @@ -57,7 +57,7 @@ protected: libvlc_media_player_t *mLibvlcMediaPlayer; public: - LibvlcCamera( int p_id, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + LibvlcCamera( int p_id, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~LibvlcCamera(); const std::string &Path() const { return( mPath ); } @@ -70,7 +70,7 @@ public: int PrimeCapture(); int PreCapture(); int Capture( Image &image ); - int CaptureAndRecord( Image &image, bool recording, char* event_directory ); + int CaptureAndRecord( Image &image, bool recording, char* event_directory ); int PostCapture(); }; diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 022f35dbe..1a22f4c8c 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -286,8 +286,26 @@ AVFrame **LocalCamera::capturePictures = 0; LocalCamera *LocalCamera::last_camera = NULL; -LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel, int p_standard, bool p_v4l_multi_buffer, unsigned int p_v4l_captures_per_frame, const std::string &p_method, int p_width, int p_height, int p_colours, int p_palette, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, unsigned int p_extras) : - Camera( p_id, LOCAL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ), +LocalCamera::LocalCamera( + int p_id, + const std::string &p_device, + int p_channel, + int p_standard, + bool p_v4l_multi_buffer, + unsigned int p_v4l_captures_per_frame, + const std::string &p_method, + int p_width, + int p_height, + int p_colours, + int p_palette, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio, + unsigned int p_extras) : + Camera( p_id, LOCAL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), device( p_device ), channel( p_channel ), standard( p_standard ), diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index f4b633a20..db9227cb4 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -116,7 +116,25 @@ protected: static LocalCamera *last_camera; public: - LocalCamera( int p_id, const std::string &device, int p_channel, int p_format, bool v4lmultibuffer, unsigned int v4lcapturesperframe, const std::string &p_method, int p_width, int p_height, int p_colours, int p_palette, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, unsigned int p_extras = 0); + LocalCamera( + int p_id, + const std::string &device, + int p_channel, + int p_format, + bool v4lmultibuffer, + unsigned int v4lcapturesperframe, + const std::string &p_method, + int p_width, + int p_height, + int p_colours, + int p_palette, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio, + unsigned int p_extras = 0); ~LocalCamera(); void Initialise(); @@ -138,7 +156,7 @@ public: int PreCapture(); int Capture( Image &image ); int PostCapture(); - int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; + int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose ); }; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp old mode 100755 new mode 100644 index c83ab7cda..4da1ce8d6 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -63,60 +63,55 @@ //============================================================================= std::vector split(const std::string &s, char delim) { - std::vector elems; - std::stringstream ss(s); - std::string item; - while(std::getline(ss, item, delim)) { - elems.push_back(trimSpaces(item)); - } - return elems; + std::vector elems; + std::stringstream ss(s); + std::string item; + while(std::getline(ss, item, delim)) { + elems.push_back(trimSpaces(item)); + } + return elems; } //============================================================================= -Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) -{ - strncpy( name, p_name, sizeof(name) ); +Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) { + strncpy( name, p_name, sizeof(name) ); #if ZM_MEM_MAPPED - map_fd = -1; - snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id ); + map_fd = -1; + snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id ); #else // ZM_MEM_MAPPED - shm_id = 0; + shm_id = 0; #endif // ZM_MEM_MAPPED - mem_size = 0; - mem_ptr = 0; + mem_size = 0; + mem_ptr = 0; - last_event = 0; - last_state = IDLE; + last_event = 0; + last_state = IDLE; - last_connect_time = 0; - connected = false; + last_connect_time = 0; + connected = false; } -Monitor::MonitorLink::~MonitorLink() -{ - disconnect(); +Monitor::MonitorLink::~MonitorLink() { + disconnect(); } -bool Monitor::MonitorLink::connect() -{ - if ( !last_connect_time || (time( 0 ) - last_connect_time) > 60 ) - { - last_connect_time = time( 0 ); +bool Monitor::MonitorLink::connect() { + if ( !last_connect_time || (time( 0 ) - last_connect_time) > 60 ) { + last_connect_time = time( 0 ); - mem_size = sizeof(SharedData) + sizeof(TriggerData); + mem_size = sizeof(SharedData) + sizeof(TriggerData); - Debug( 1, "link.mem.size=%d", mem_size ); + Debug( 1, "link.mem.size=%d", mem_size ); #if ZM_MEM_MAPPED - map_fd = open( mem_file, O_RDWR, (mode_t)0600 ); - if ( map_fd < 0 ) - { - Debug( 3, "Can't open linked memory map file %s: %s", mem_file, strerror(errno) ); - disconnect(); - return( false ); - } + map_fd = open( mem_file, O_RDWR, (mode_t)0600 ); + if ( map_fd < 0 ) { + Debug( 3, "Can't open linked memory map file %s: %s", mem_file, strerror(errno) ); + disconnect(); + return( false ); + } while ( map_fd <= 2 ) { int new_map_fd = dup(map_fd); Warning( "Got one of the stdio fds for our mmap handle. map_fd was %d, new one is %d", map_fd, new_map_fd ); @@ -124,431 +119,405 @@ bool Monitor::MonitorLink::connect() map_fd = new_map_fd; } - struct stat map_stat; - if ( fstat( map_fd, &map_stat ) < 0 ) - { - Error( "Can't stat linked memory map file %s: %s", mem_file, strerror(errno) ); - disconnect(); - return( false ); - } + struct stat map_stat; + if ( fstat( map_fd, &map_stat ) < 0 ) { + Error( "Can't stat linked memory map file %s: %s", mem_file, strerror(errno) ); + disconnect(); + return( false ); + } - if ( map_stat.st_size == 0 ) - { - Error( "Linked memory map file %s is empty: %s", mem_file, strerror(errno) ); - disconnect(); - return( false ); - } - else if ( map_stat.st_size < mem_size ) - { - Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size ); - disconnect(); - return( false ); - } + if ( map_stat.st_size == 0 ) { + Error( "Linked memory map file %s is empty: %s", mem_file, strerror(errno) ); + disconnect(); + return( false ); + } else if ( map_stat.st_size < mem_size ) { + Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size ); + disconnect(); + return( false ); + } - mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 ); - if ( mem_ptr == MAP_FAILED ) - { - Error( "Can't map file %s (%d bytes) to memory: %s", mem_file, mem_size, strerror(errno) ); - disconnect(); - return( false ); - } + mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 ); + if ( mem_ptr == MAP_FAILED ) { + Error( "Can't map file %s (%d bytes) to memory: %s", mem_file, mem_size, strerror(errno) ); + disconnect(); + return( false ); + } #else // ZM_MEM_MAPPED - shm_id = shmget( (config.shm_key&0xffff0000)|id, mem_size, 0700 ); - if ( shm_id < 0 ) - { - Debug( 3, "Can't shmget link memory: %s", strerror(errno) ); - connected = false; - return( false ); - } - mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 ); - if ( mem_ptr < 0 ) - { - Debug( 3, "Can't shmat link memory: %s", strerror(errno) ); - connected = false; - return( false ); - } + shm_id = shmget( (config.shm_key&0xffff0000)|id, mem_size, 0700 ); + if ( shm_id < 0 ) { + Debug( 3, "Can't shmget link memory: %s", strerror(errno) ); + connected = false; + return( false ); + } + mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 ); + if ( mem_ptr < 0 ) { + Debug( 3, "Can't shmat link memory: %s", strerror(errno) ); + connected = false; + return( false ); + } #endif // ZM_MEM_MAPPED - shared_data = (SharedData *)mem_ptr; - trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData)); + shared_data = (SharedData *)mem_ptr; + trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData)); - if ( !shared_data->valid ) - { - Debug( 3, "Linked memory not initialised by capture daemon" ); - disconnect(); - return( false ); - } + if ( !shared_data->valid ) { + Debug( 3, "Linked memory not initialised by capture daemon" ); + disconnect(); + return( false ); + } - last_state = shared_data->state; - last_event = shared_data->last_event; - connected = true; + last_state = shared_data->state; + last_event = shared_data->last_event; + connected = true; - return( true ); - } - return( false ); + return( true ); + } + return( false ); } -bool Monitor::MonitorLink::disconnect() -{ - if ( connected ) - { - connected = false; +bool Monitor::MonitorLink::disconnect() { + if ( connected ) { + connected = false; #if ZM_MEM_MAPPED - if ( mem_ptr > 0 ) - { - msync( mem_ptr, mem_size, MS_ASYNC ); - munmap( mem_ptr, mem_size ); - } - if ( map_fd >= 0 ) - close( map_fd ); + if ( mem_ptr > 0 ) { + msync( mem_ptr, mem_size, MS_ASYNC ); + munmap( mem_ptr, mem_size ); + } + if ( map_fd >= 0 ) + close( map_fd ); - map_fd = -1; + map_fd = -1; #else // ZM_MEM_MAPPED - struct shmid_ds shm_data; - if ( shmctl( shm_id, IPC_STAT, &shm_data ) < 0 ) - { - Debug( 3, "Can't shmctl: %s", strerror(errno) ); - return( false ); - } + struct shmid_ds shm_data; + if ( shmctl( shm_id, IPC_STAT, &shm_data ) < 0 ) { + Debug( 3, "Can't shmctl: %s", strerror(errno) ); + return( false ); + } - shm_id = 0; + shm_id = 0; - if ( shm_data.shm_nattch <= 1 ) - { - if ( shmctl( shm_id, IPC_RMID, 0 ) < 0 ) - { - Debug( 3, "Can't shmctl: %s", strerror(errno) ); - return( false ); - } - } + if ( shm_data.shm_nattch <= 1 ) { + if ( shmctl( shm_id, IPC_RMID, 0 ) < 0 ) { + Debug( 3, "Can't shmctl: %s", strerror(errno) ); + return( false ); + } + } - if ( shmdt( mem_ptr ) < 0 ) - { - Debug( 3, "Can't shmdt: %s", strerror(errno) ); - return( false ); - } + if ( shmdt( mem_ptr ) < 0 ) { + Debug( 3, "Can't shmdt: %s", strerror(errno) ); + return( false ); + } #endif // ZM_MEM_MAPPED - mem_size = 0; - mem_ptr = 0; - } - return( true ); + mem_size = 0; + mem_ptr = 0; + } + return( true ); } -bool Monitor::MonitorLink::isAlarmed() -{ - if ( !connected ) - { - return( false ); - } - return( shared_data->state == ALARM ); +bool Monitor::MonitorLink::isAlarmed() { + if ( !connected ) { + return( false ); + } + return( shared_data->state == ALARM ); } -bool Monitor::MonitorLink::inAlarm() -{ - if ( !connected ) - { - return( false ); - } - return( shared_data->state == ALARM || shared_data->state == ALERT ); +bool Monitor::MonitorLink::inAlarm() { + if ( !connected ) { + return( false ); + } + return( shared_data->state == ALARM || shared_data->state == ALERT ); } bool Monitor::MonitorLink::hasAlarmed() { - if ( shared_data->state == ALARM ) - { - return( true ); - } - else if( shared_data->last_event != (unsigned int)last_event ) - { - last_event = shared_data->last_event; - } - return( false ); + if ( shared_data->state == ALARM ) { + return( true ); + } else if ( shared_data->last_event != (unsigned int)last_event ) { + last_event = shared_data->last_event; + } + return( false ); } Monitor::Monitor( - int p_id, - const char *p_name, - const unsigned int p_server_id, - int p_function, - bool p_enabled, - const char *p_linked_monitors, - Camera *p_camera, - int p_orientation, - unsigned int p_deinterlacing, - int p_savejpegs, - int p_videowriter, - std::string p_encoderparams, - const char *p_event_prefix, - const char *p_label_format, - const Coord &p_label_coord, - int p_label_size, - int p_image_buffer_count, - int p_warmup_count, - int p_pre_event_count, - int p_post_event_count, - int p_stream_replay_buffer, - int p_alarm_frame_count, - int p_section_length, - int p_frame_skip, - int p_motion_frame_skip, - double p_analysis_fps, - unsigned int p_analysis_update_delay, - int p_capture_delay, - int p_alarm_capture_delay, - int p_fps_report_interval, - int p_ref_blend_perc, - int p_alarm_ref_blend_perc, - bool p_track_motion, - Rgb p_signal_check_colour, - bool p_embed_exif, - Purpose p_purpose, - int p_n_zones, - Zone *p_zones[] + int p_id, + const char *p_name, + const unsigned int p_server_id, + int p_function, + bool p_enabled, + const char *p_linked_monitors, + Camera *p_camera, + int p_orientation, + unsigned int p_deinterlacing, + int p_savejpegs, + int p_videowriter, + std::string p_encoderparams, + bool p_record_audio, + const char *p_event_prefix, + const char *p_label_format, + const Coord &p_label_coord, + int p_label_size, + int p_image_buffer_count, + int p_warmup_count, + int p_pre_event_count, + int p_post_event_count, + int p_stream_replay_buffer, + int p_alarm_frame_count, + int p_section_length, + int p_frame_skip, + int p_motion_frame_skip, + double p_analysis_fps, + unsigned int p_analysis_update_delay, + int p_capture_delay, + int p_alarm_capture_delay, + int p_fps_report_interval, + int p_ref_blend_perc, + int p_alarm_ref_blend_perc, + bool p_track_motion, + Rgb p_signal_check_colour, + bool p_embed_exif, + Purpose p_purpose, + int p_n_zones, + Zone *p_zones[] ) : id( p_id ), - server_id( p_server_id ), - function( (Function)p_function ), - enabled( p_enabled ), - width( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Height():p_camera->Width() ), - height( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Width():p_camera->Height() ), - orientation( (Orientation)p_orientation ), - deinterlacing( p_deinterlacing ), - savejpegspref( p_savejpegs ), - videowriterpref( p_videowriter ), - encoderparams( p_encoderparams ), - label_coord( p_label_coord ), - label_size( p_label_size ), - image_buffer_count( p_image_buffer_count ), - warmup_count( p_warmup_count ), - pre_event_count( p_pre_event_count ), - post_event_count( p_post_event_count ), - stream_replay_buffer( p_stream_replay_buffer ), - section_length( p_section_length ), - frame_skip( p_frame_skip ), - motion_frame_skip( p_motion_frame_skip ), - analysis_fps( p_analysis_fps ), - analysis_update_delay( p_analysis_update_delay ), - capture_delay( p_capture_delay ), - alarm_capture_delay( p_alarm_capture_delay ), - alarm_frame_count( p_alarm_frame_count ), - fps_report_interval( p_fps_report_interval ), - ref_blend_perc( p_ref_blend_perc ), - alarm_ref_blend_perc( p_alarm_ref_blend_perc ), - track_motion( p_track_motion ), - signal_check_colour( p_signal_check_colour ), - embed_exif( p_embed_exif ), - delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ), - ref_image( width, height, p_camera->Colours(), p_camera->SubpixelOrder() ), - purpose( p_purpose ), - last_motion_score(0), - camera( p_camera ), - n_zones( p_n_zones ), - zones( p_zones ), - timestamps( 0 ), - images( 0 ), - privacy_bitmask( NULL ) + server_id( p_server_id ), + function( (Function)p_function ), + enabled( p_enabled ), + width( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Height():p_camera->Width() ), + height( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Width():p_camera->Height() ), + orientation( (Orientation)p_orientation ), + deinterlacing( p_deinterlacing ), + savejpegspref( p_savejpegs ), + videowriterpref( p_videowriter ), + encoderparams( p_encoderparams ), + record_audio( p_record_audio ), + label_coord( p_label_coord ), + label_size( p_label_size ), + image_buffer_count( p_image_buffer_count ), + warmup_count( p_warmup_count ), + pre_event_count( p_pre_event_count ), + post_event_count( p_post_event_count ), + stream_replay_buffer( p_stream_replay_buffer ), + section_length( p_section_length ), + frame_skip( p_frame_skip ), + motion_frame_skip( p_motion_frame_skip ), + analysis_fps( p_analysis_fps ), + analysis_update_delay( p_analysis_update_delay ), + capture_delay( p_capture_delay ), + alarm_capture_delay( p_alarm_capture_delay ), + alarm_frame_count( p_alarm_frame_count ), + fps_report_interval( p_fps_report_interval ), + ref_blend_perc( p_ref_blend_perc ), + alarm_ref_blend_perc( p_alarm_ref_blend_perc ), + track_motion( p_track_motion ), + signal_check_colour( p_signal_check_colour ), + embed_exif( p_embed_exif ), + delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ), + ref_image( width, height, p_camera->Colours(), p_camera->SubpixelOrder() ), + purpose( p_purpose ), + last_motion_score(0), + camera( p_camera ), + n_zones( p_n_zones ), + zones( p_zones ), + timestamps( 0 ), + images( 0 ), + privacy_bitmask( NULL ) { - strncpy( name, p_name, sizeof(name)-1 ); + strncpy( name, p_name, sizeof(name)-1 ); - strncpy( event_prefix, p_event_prefix, sizeof(event_prefix)-1 ); - strncpy( label_format, p_label_format, sizeof(label_format)-1 ); + strncpy( event_prefix, p_event_prefix, sizeof(event_prefix)-1 ); + strncpy( label_format, p_label_format, sizeof(label_format)-1 ); - // Change \n to actual line feeds - char *token_ptr = label_format; - const char *token_string = "\n"; - while( ( token_ptr = strstr( token_ptr, token_string ) ) ) - { - if ( *(token_ptr+1) ) - { - *token_ptr = '\n'; - token_ptr++; - strcpy( token_ptr, token_ptr+1 ); - } - else - { - *token_ptr = '\0'; - break; - } - } + // Change \n to actual line feeds + char *token_ptr = label_format; + const char *token_string = "\n"; + while( ( token_ptr = strstr( token_ptr, token_string ) ) ) + { + if ( *(token_ptr+1) ) + { + *token_ptr = '\n'; + token_ptr++; + strcpy( token_ptr, token_ptr+1 ); + } + else + { + *token_ptr = '\0'; + break; + } + } - /* Parse encoder parameters */ - ParseEncoderParameters(encoderparams.c_str(), &encoderparamsvec); + /* Parse encoder parameters */ + ParseEncoderParameters(encoderparams.c_str(), &encoderparamsvec); - fps = 0.0; - event_count = 0; - image_count = 0; - ready_count = warmup_count; - first_alarm_count = 0; - last_alarm_count = 0; - state = IDLE; + fps = 0.0; + event_count = 0; + image_count = 0; + ready_count = warmup_count; + first_alarm_count = 0; + last_alarm_count = 0; + state = IDLE; - if ( alarm_frame_count < 1 ) - alarm_frame_count = 1; - else if ( alarm_frame_count > MAX_PRE_ALARM_FRAMES ) - alarm_frame_count = MAX_PRE_ALARM_FRAMES; + if ( alarm_frame_count < 1 ) + alarm_frame_count = 1; + else if ( alarm_frame_count > MAX_PRE_ALARM_FRAMES ) + alarm_frame_count = MAX_PRE_ALARM_FRAMES; - auto_resume_time = 0; + auto_resume_time = 0; - if ( strcmp( config.event_close_mode, "time" ) == 0 ) - event_close_mode = CLOSE_TIME; - else if ( strcmp( config.event_close_mode, "alarm" ) == 0 ) - event_close_mode = CLOSE_ALARM; - else - event_close_mode = CLOSE_IDLE; + if ( strcmp( config.event_close_mode, "time" ) == 0 ) + event_close_mode = CLOSE_TIME; + else if ( strcmp( config.event_close_mode, "alarm" ) == 0 ) + event_close_mode = CLOSE_ALARM; + else + event_close_mode = CLOSE_IDLE; - Debug( 1, "monitor purpose=%d", purpose ); + Debug( 1, "monitor purpose=%d", purpose ); - mem_size = sizeof(SharedData) - + sizeof(TriggerData) - + sizeof(VideoStoreData) //Information to pass back to the capture process - + (image_buffer_count*sizeof(struct timeval)) - + (image_buffer_count*camera->ImageSize()) - + 64; /* Padding used to permit aligning the images buffer to 16 byte boundary */ + mem_size = sizeof(SharedData) + + sizeof(TriggerData) + + sizeof(VideoStoreData) //Information to pass back to the capture process + + (image_buffer_count*sizeof(struct timeval)) + + (image_buffer_count*camera->ImageSize()) + + 64; /* Padding used to permit aligning the images buffer to 16 byte boundary */ - Debug( 1, "mem.size=%d", mem_size ); + Debug( 1, "mem.size=%d", mem_size ); mem_ptr = NULL; - if ( purpose == CAPTURE ) { + if ( purpose == CAPTURE ) { this->connect(); if ( ! mem_ptr ) exit(-1); - memset( mem_ptr, 0, mem_size ); - shared_data->size = sizeof(SharedData); - shared_data->active = enabled; - shared_data->signal = false; - shared_data->state = IDLE; - shared_data->last_write_index = image_buffer_count; - shared_data->last_read_index = image_buffer_count; - shared_data->last_write_time = 0; - shared_data->last_event = 0; - shared_data->action = (Action)0; - shared_data->brightness = -1; - shared_data->hue = -1; - shared_data->colour = -1; - shared_data->contrast = -1; - shared_data->alarm_x = -1; - shared_data->alarm_y = -1; - shared_data->format = camera->SubpixelOrder(); - shared_data->imagesize = camera->ImageSize(); - trigger_data->size = sizeof(TriggerData); - trigger_data->trigger_state = TRIGGER_CANCEL; - trigger_data->trigger_score = 0; - trigger_data->trigger_cause[0] = 0; - trigger_data->trigger_text[0] = 0; - trigger_data->trigger_showtext[0] = 0; - shared_data->valid = true; - video_store_data->recording = false; - snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "nothing"); - video_store_data->size = sizeof(VideoStoreData); - //video_store_data->frameNumber = 0; - } else if ( purpose == ANALYSIS ) { + memset( mem_ptr, 0, mem_size ); + shared_data->size = sizeof(SharedData); + shared_data->active = enabled; + shared_data->signal = false; + shared_data->state = IDLE; + shared_data->last_write_index = image_buffer_count; + shared_data->last_read_index = image_buffer_count; + shared_data->last_write_time = 0; + shared_data->last_event = 0; + shared_data->action = (Action)0; + shared_data->brightness = -1; + shared_data->hue = -1; + shared_data->colour = -1; + shared_data->contrast = -1; + shared_data->alarm_x = -1; + shared_data->alarm_y = -1; + shared_data->format = camera->SubpixelOrder(); + shared_data->imagesize = camera->ImageSize(); + trigger_data->size = sizeof(TriggerData); + trigger_data->trigger_state = TRIGGER_CANCEL; + trigger_data->trigger_score = 0; + trigger_data->trigger_cause[0] = 0; + trigger_data->trigger_text[0] = 0; + trigger_data->trigger_showtext[0] = 0; + shared_data->valid = true; + video_store_data->recording = false; + snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "nothing"); + video_store_data->size = sizeof(VideoStoreData); + //video_store_data->frameNumber = 0; + } else if ( purpose == ANALYSIS ) { this->connect(); if ( ! mem_ptr ) exit(-1); - shared_data->state = IDLE; - shared_data->last_read_time = 0; - shared_data->alarm_x = -1; - shared_data->alarm_y = -1; - } + shared_data->state = IDLE; + shared_data->last_read_time = 0; + shared_data->alarm_x = -1; + shared_data->alarm_y = -1; + } - if ( ( ! mem_ptr ) || ! shared_data->valid ) - { - if ( purpose != QUERY ) - { - Error( "Shared data not initialised by capture daemon for monitor %s", name ); - exit( -1 ); - } - } + if ( ( ! mem_ptr ) || ! shared_data->valid ) { + if ( purpose != QUERY ) { + Error( "Shared data not initialised by capture daemon for monitor %s", name ); + exit( -1 ); + } + } // Will this not happen every time a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after.. - if ( !n_zones ) { + // In my storage areas branch, I took this out.. and didn't notice any problems. + if ( !n_zones ) { Debug( 1, "Monitor %s has no zones, adding one.", name ); - n_zones = 1; - zones = new Zone *[1]; - Coord coords[4] = { Coord( 0, 0 ), Coord( width-1, 0 ), Coord( width-1, height-1 ), Coord( 0, height-1 ) }; - zones[0] = new Zone( this, 0, "All", Zone::ACTIVE, Polygon( sizeof(coords)/sizeof(*coords), coords ), RGB_RED, Zone::BLOBS ); - } - start_time = last_fps_time = time( 0 ); + n_zones = 1; + zones = new Zone *[1]; + Coord coords[4] = { Coord( 0, 0 ), Coord( width-1, 0 ), Coord( width-1, height-1 ), Coord( 0, height-1 ) }; + zones[0] = new Zone( this, 0, "All", Zone::ACTIVE, Polygon( sizeof(coords)/sizeof(*coords), coords ), RGB_RED, Zone::BLOBS ); + } + start_time = last_fps_time = time( 0 ); - event = 0; + event = 0; - Debug( 1, "Monitor %s has function %d", name, function ); - Debug( 1, "Monitor %s LBF = '%s', LBX = %d, LBY = %d, LBS = %d", name, label_format, label_coord.X(), label_coord.Y(), label_size ); - Debug( 1, "Monitor %s IBC = %d, WUC = %d, pEC = %d, PEC = %d, EAF = %d, FRI = %d, RBP = %d, ARBP = %d, FM = %d", name, image_buffer_count, warmup_count, pre_event_count, post_event_count, alarm_frame_count, fps_report_interval, ref_blend_perc, alarm_ref_blend_perc, track_motion ); + Debug( 1, "Monitor %s has function %d", name, function ); + Debug( 1, "Monitor %s LBF = '%s', LBX = %d, LBY = %d, LBS = %d", name, label_format, label_coord.X(), label_coord.Y(), label_size ); + Debug( 1, "Monitor %s IBC = %d, WUC = %d, pEC = %d, PEC = %d, EAF = %d, FRI = %d, RBP = %d, ARBP = %d, FM = %d", name, image_buffer_count, warmup_count, pre_event_count, post_event_count, alarm_frame_count, fps_report_interval, ref_blend_perc, alarm_ref_blend_perc, track_motion ); - if ( purpose == ANALYSIS ) - { - static char path[PATH_MAX]; + if ( purpose == ANALYSIS ) { + static char path[PATH_MAX]; - strncpy( path, config.dir_events, sizeof(path) ); + strncpy( path, config.dir_events, sizeof(path) ); - struct stat statbuf; - errno = 0; - stat( path, &statbuf ); - if ( errno == ENOENT || errno == ENOTDIR ) - { - if ( mkdir( path, 0755 ) ) - { - Error( "Can't make %s: %s", path, strerror(errno)); - } - } + struct stat statbuf; + errno = 0; + stat( path, &statbuf ); + if ( errno == ENOENT || errno == ENOTDIR ) { + if ( mkdir( path, 0755 ) ) + { + Error( "Can't make %s: %s", path, strerror(errno)); + } + } - snprintf( path, sizeof(path), "%s/%d", config.dir_events, id ); + snprintf( path, sizeof(path), "%s/%d", config.dir_events, id ); - errno = 0; - stat( path, &statbuf ); - if ( errno == ENOENT || errno == ENOTDIR ) - { - if ( mkdir( path, 0755 ) ) - { - Error( "Can't make %s: %s", path, strerror(errno)); - } - char temp_path[PATH_MAX]; - snprintf( temp_path, sizeof(temp_path), "%d", id ); - if ( chdir( config.dir_events ) < 0 ) - Fatal( "Can't change directory to '%s': %s", config.dir_events, strerror(errno) ); - if ( symlink( temp_path, name ) < 0 ) - Fatal( "Can't symlink '%s' to '%s': %s", temp_path, name, strerror(errno) ); - if ( chdir( ".." ) < 0 ) - Fatal( "Can't change to parent directory: %s", strerror(errno) ); - } + errno = 0; + stat( path, &statbuf ); + if ( errno == ENOENT || errno == ENOTDIR ) { + if ( mkdir( path, 0755 ) ) { + Error( "Can't make %s: %s", path, strerror(errno)); + } + char temp_path[PATH_MAX]; + snprintf( temp_path, sizeof(temp_path), "%d", id ); + if ( chdir( config.dir_events ) < 0 ) + Fatal( "Can't change directory to '%s': %s", config.dir_events, strerror(errno) ); + if ( symlink( temp_path, name ) < 0 ) + Fatal( "Can't symlink '%s' to '%s': %s", temp_path, name, strerror(errno) ); + if ( chdir( ".." ) < 0 ) + Fatal( "Can't change to parent directory: %s", strerror(errno) ); + } - while( shared_data->last_write_index == (unsigned int)image_buffer_count - && shared_data->last_write_time == 0) - { - Warning( "Waiting for capture daemon" ); - sleep( 1 ); - } - ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); + while( shared_data->last_write_index == (unsigned int)image_buffer_count + && shared_data->last_write_time == 0) { + Warning( "Waiting for capture daemon" ); + sleep( 1 ); + } + ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); - n_linked_monitors = 0; - linked_monitors = 0; + n_linked_monitors = 0; + linked_monitors = 0; - adaptive_skip = true; + adaptive_skip = true; - ReloadLinkedMonitors( p_linked_monitors ); - } + ReloadLinkedMonitors( p_linked_monitors ); + } } bool Monitor::connect() { #if ZM_MEM_MAPPED - snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id ); - map_fd = open( mem_file, O_RDWR|O_CREAT, (mode_t)0600 ); - if ( map_fd < 0 ) - Fatal( "Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno) ); + snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id ); + map_fd = open( mem_file, O_RDWR|O_CREAT, (mode_t)0600 ); + if ( map_fd < 0 ) + Fatal( "Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno) ); - struct stat map_stat; - if ( fstat( map_fd, &map_stat ) < 0 ) - Fatal( "Can't stat memory map file %s: %s, is the zmc process for this monitor running?", mem_file, strerror(errno) ); - if ( map_stat.st_size != mem_size && purpose == CAPTURE ) { - // Allocate the size - if ( ftruncate( map_fd, mem_size ) < 0 ) { - Fatal( "Can't extend memory map file %s to %d bytes: %s", mem_file, mem_size, strerror(errno) ); + struct stat map_stat; + if ( fstat( map_fd, &map_stat ) < 0 ) + Fatal( "Can't stat memory map file %s: %s, is the zmc process for this monitor running?", mem_file, strerror(errno) ); + if ( map_stat.st_size != mem_size && purpose == CAPTURE ) { + // Allocate the size + if ( ftruncate( map_fd, mem_size ) < 0 ) { + Fatal( "Can't extend memory map file %s to %d bytes: %s", mem_file, mem_size, strerror(errno) ); } - } else if ( map_stat.st_size == 0 ) { - Error( "Got empty memory map file size %ld, is the zmc process for this monitor running?", map_stat.st_size, mem_size ); + } else if ( map_stat.st_size == 0 ) { + Error( "Got empty memory map file size %ld, is the zmc process for this monitor running?", map_stat.st_size, mem_size ); return false; - } else if ( map_stat.st_size != mem_size ) { - Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size ); + } else if ( map_stat.st_size != mem_size ) { + Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size ); return false; } else { #ifdef MAP_LOCKED @@ -565,59 +534,54 @@ bool Monitor::connect() { #endif if ( mem_ptr == MAP_FAILED ) Fatal( "Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno ); - } + } #else // ZM_MEM_MAPPED - shm_id = shmget( (config.shm_key&0xffff0000)|id, mem_size, IPC_CREAT|0700 ); - if ( shm_id < 0 ) { - Error( "Can't shmget, probably not enough shared memory space free: %s", strerror(errno)); - exit( -1 ); - } - mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 ); - if ( mem_ptr < 0 ) - { - Error( "Can't shmat: %s", strerror(errno)); - exit( -1 ); - } + shm_id = shmget( (config.shm_key&0xffff0000)|id, mem_size, IPC_CREAT|0700 ); + if ( shm_id < 0 ) { + Error( "Can't shmget, probably not enough shared memory space free: %s", strerror(errno)); + exit( -1 ); + } + mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 ); + if ( mem_ptr < 0 ) { + Error( "Can't shmat: %s", strerror(errno)); + exit( -1 ); + } #endif // ZM_MEM_MAPPED - shared_data = (SharedData *)mem_ptr; - trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData)); - video_store_data = (VideoStoreData *)((char *)trigger_data + sizeof(TriggerData)); - struct timeval *shared_timestamps = (struct timeval *)((char *)video_store_data + sizeof(VideoStoreData)); - unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval))); - - if(((unsigned long)shared_images % 16) != 0) { + shared_data = (SharedData *)mem_ptr; + trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData)); + video_store_data = (VideoStoreData *)((char *)trigger_data + sizeof(TriggerData)); + struct timeval *shared_timestamps = (struct timeval *)((char *)video_store_data + sizeof(VideoStoreData)); + unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval))); + + if(((unsigned long)shared_images % 16) != 0) { /* Align images buffer to nearest 16 byte boundary */ Debug(3,"Aligning shared memory images to the next 16 byte boundary"); shared_images = (uint8_t*)((unsigned long)shared_images + (16 - ((unsigned long)shared_images % 16))); - } - image_buffer = new Snapshot[image_buffer_count]; - for ( int i = 0; i < image_buffer_count; i++ ) - { - image_buffer[i].timestamp = &(shared_timestamps[i]); - 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 ( (deinterlacing & 0xff) == 4) - { - /* Four field motion adaptive deinterlacing in use */ - /* Allocate a buffer for the next image */ - next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); - next_buffer.timestamp = new struct timeval; - } + } + image_buffer = new Snapshot[image_buffer_count]; + for ( int i = 0; i < image_buffer_count; i++ ) { + image_buffer[i].timestamp = &(shared_timestamps[i]); + 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 ( (deinterlacing & 0xff) == 4) { + /* Four field motion adaptive deinterlacing in use */ + /* Allocate a buffer for the next image */ + next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + next_buffer.timestamp = new struct timeval; + } - if ( ( purpose == ANALYSIS ) && analysis_fps ) - { - // Size of pre event buffer must be greater than pre_event_count - // if alarm_frame_count > 1, because in this case the buffer contains - // alarmed images that must be discarded when event is created - pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; - pre_event_buffer = new Snapshot[pre_event_buffer_count]; - for ( int i = 0; i < pre_event_buffer_count; i++ ) - { - pre_event_buffer[i].timestamp = new struct timeval; - pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); - } - } + if ( ( purpose == ANALYSIS ) && analysis_fps ) { + // Size of pre event buffer must be greater than pre_event_count + // if alarm_frame_count > 1, because in this case the buffer contains + // alarmed images that must be discarded when event is created + pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; + pre_event_buffer = new Snapshot[pre_event_buffer_count]; + for ( int i = 0; i < pre_event_buffer_count; i++ ) { + pre_event_buffer[i].timestamp = new struct timeval; + pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + } + } return true; } @@ -632,10 +596,10 @@ Monitor::~Monitor() delete[] images; images = 0; } - if ( privacy_bitmask ) { - delete[] privacy_bitmask; - privacy_bitmask = NULL; - } + if ( privacy_bitmask ) { + delete[] privacy_bitmask; + privacy_bitmask = NULL; + } if ( mem_ptr ) { if ( event ) Info( "%s: %03d - Closing event %d, shutting down", name, image_count, event->Id() ); @@ -653,13 +617,13 @@ Monitor::~Monitor() delete[] image_buffer; } // end if mem_ptr - for ( int i = 0; i < n_zones; i++ ) - { - delete zones[i]; - } - delete[] zones; + for ( int i = 0; i < n_zones; i++ ) + { + delete zones[i]; + } + delete[] zones; - delete camera; + delete camera; if ( mem_ptr ) { if ( purpose == ANALYSIS ) @@ -708,552 +672,552 @@ Monitor::~Monitor() void Monitor::AddZones( int p_n_zones, Zone *p_zones[] ) { - for ( int i = 0; i < n_zones; i++ ) - delete zones[i]; - delete[] zones; - n_zones = p_n_zones; - zones = p_zones; + for ( int i = 0; i < n_zones; i++ ) + delete zones[i]; + delete[] zones; + n_zones = p_n_zones; + zones = p_zones; } void Monitor::AddPrivacyBitmask( Zone *p_zones[] ) { if ( privacy_bitmask ) delete[] privacy_bitmask; - privacy_bitmask = NULL; - Image *privacy_image = NULL; + privacy_bitmask = NULL; + Image *privacy_image = NULL; - for ( int i = 0; i < n_zones; i++ ) - { - if ( p_zones[i]->IsPrivacy() ) - { - if ( !privacy_image ) - { - privacy_image = new Image( width, height, 1, ZM_SUBPIX_ORDER_NONE); - privacy_image->Clear(); - } - privacy_image->Fill( 0xff, p_zones[i]->GetPolygon() ); - privacy_image->Outline( 0xff, p_zones[i]->GetPolygon() ); - } - } // end foreach zone - if ( privacy_image ) - privacy_bitmask = privacy_image->Buffer(); + for ( int i = 0; i < n_zones; i++ ) + { + if ( p_zones[i]->IsPrivacy() ) + { + if ( !privacy_image ) + { + privacy_image = new Image( width, height, 1, ZM_SUBPIX_ORDER_NONE); + privacy_image->Clear(); + } + privacy_image->Fill( 0xff, p_zones[i]->GetPolygon() ); + privacy_image->Outline( 0xff, p_zones[i]->GetPolygon() ); + } + } // end foreach zone + if ( privacy_image ) + privacy_bitmask = privacy_image->Buffer(); } Monitor::State Monitor::GetState() const { - return( (State)shared_data->state ); + return( (State)shared_data->state ); } int Monitor::GetImage( int index, int scale ) { - if ( index < 0 || index > image_buffer_count ) - { - index = shared_data->last_write_index; - } + if ( index < 0 || index > image_buffer_count ) + { + index = shared_data->last_write_index; + } - if ( index != image_buffer_count ) - { - Image *image; + if ( index != image_buffer_count ) + { + Image *image; // 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 ) ) { - Snapshot *snap = &image_buffer[index]; - Image *snap_image = snap->image; + if ( ( scale != ZM_SCALE_BASE ) || ( !config.timestamp_on_capture ) ) { + Snapshot *snap = &image_buffer[index]; + Image *snap_image = snap->image; - alarm_image.Assign( *snap_image ); + alarm_image.Assign( *snap_image ); - //write_image.Assign( *snap_image ); + //write_image.Assign( *snap_image ); - if ( scale != ZM_SCALE_BASE ) { - alarm_image.Scale( scale ); - } + if ( scale != ZM_SCALE_BASE ) { + alarm_image.Scale( scale ); + } - if ( !config.timestamp_on_capture ) { - TimestampImage( &alarm_image, snap->timestamp ); - } - image = &alarm_image; - } else { - image = image_buffer[index].image; - } + if ( !config.timestamp_on_capture ) { + TimestampImage( &alarm_image, snap->timestamp ); + } + image = &alarm_image; + } else { + image = image_buffer[index].image; + } - static char filename[PATH_MAX]; - snprintf( filename, sizeof(filename), "Monitor%d.jpg", id ); - image->WriteJpeg( filename ); - } - else - { - Error( "Unable to generate image, no images in buffer" ); - } - return( 0 ); + static char filename[PATH_MAX]; + snprintf( filename, sizeof(filename), "Monitor%d.jpg", id ); + image->WriteJpeg( filename ); + } + else + { + Error( "Unable to generate image, no images in buffer" ); + } + return( 0 ); } struct timeval Monitor::GetTimestamp( int index ) const { - if ( index < 0 || index > image_buffer_count ) - { - index = shared_data->last_write_index; - } + if ( index < 0 || index > image_buffer_count ) + { + index = shared_data->last_write_index; + } - if ( index != image_buffer_count ) - { - Snapshot *snap = &image_buffer[index]; + if ( index != image_buffer_count ) + { + Snapshot *snap = &image_buffer[index]; - return( *(snap->timestamp) ); - } - else - { - static struct timeval null_tv = { 0, 0 }; + return( *(snap->timestamp) ); + } + else + { + static struct timeval null_tv = { 0, 0 }; - return( null_tv ); - } + return( null_tv ); + } } unsigned int Monitor::GetLastReadIndex() const { - return( shared_data->last_read_index!=(unsigned int)image_buffer_count?shared_data->last_read_index:-1 ); + return( shared_data->last_read_index!=(unsigned int)image_buffer_count?shared_data->last_read_index:-1 ); } unsigned int Monitor::GetLastWriteIndex() const { - return( shared_data->last_write_index!=(unsigned int)image_buffer_count?shared_data->last_write_index:-1 ); + return( shared_data->last_write_index!=(unsigned int)image_buffer_count?shared_data->last_write_index:-1 ); } unsigned int Monitor::GetLastEvent() const { - return( shared_data->last_event ); + return( shared_data->last_event ); } double Monitor::GetFPS() const { - int index1 = shared_data->last_write_index; - if ( index1 == image_buffer_count ) - { - return( 0.0 ); - } - Snapshot *snap1 = &image_buffer[index1]; - if ( !snap1->timestamp || !snap1->timestamp->tv_sec ) - { - return( 0.0 ); - } - struct timeval time1 = *snap1->timestamp; + int index1 = shared_data->last_write_index; + if ( index1 == image_buffer_count ) + { + return( 0.0 ); + } + Snapshot *snap1 = &image_buffer[index1]; + if ( !snap1->timestamp || !snap1->timestamp->tv_sec ) + { + return( 0.0 ); + } + struct timeval time1 = *snap1->timestamp; - int image_count = image_buffer_count; - int index2 = (index1+1)%image_buffer_count; - if ( index2 == image_buffer_count ) - { - return( 0.0 ); - } - Snapshot *snap2 = &image_buffer[index2]; - while ( !snap2->timestamp || !snap2->timestamp->tv_sec ) - { - if ( index1 == index2 ) - { - return( 0.0 ); - } - index2 = (index2+1)%image_buffer_count; - snap2 = &image_buffer[index2]; - image_count--; - } - struct timeval time2 = *snap2->timestamp; + int image_count = image_buffer_count; + int index2 = (index1+1)%image_buffer_count; + if ( index2 == image_buffer_count ) + { + return( 0.0 ); + } + Snapshot *snap2 = &image_buffer[index2]; + while ( !snap2->timestamp || !snap2->timestamp->tv_sec ) + { + if ( index1 == index2 ) + { + return( 0.0 ); + } + index2 = (index2+1)%image_buffer_count; + snap2 = &image_buffer[index2]; + image_count--; + } + struct timeval time2 = *snap2->timestamp; - double time_diff = tvDiffSec( time2, time1 ); + double time_diff = tvDiffSec( time2, time1 ); - double curr_fps = image_count/time_diff; + double curr_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 ); - } - return( curr_fps ); + 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 ); + } + return( curr_fps ); } useconds_t Monitor::GetAnalysisRate() { - double capturing_fps = GetFPS(); - if ( !analysis_fps ) - { - return( 0 ); - } - else if ( analysis_fps > capturing_fps ) - { - Warning( "Analysis fps (%.2f) is greater than capturing fps (%.2f)", analysis_fps, capturing_fps ); - return( 0 ); - } - else - { - return( ( 1000000 / analysis_fps ) - ( 1000000 / capturing_fps ) ); - } + double capturing_fps = GetFPS(); + if ( !analysis_fps ) + { + return( 0 ); + } + else if ( analysis_fps > capturing_fps ) + { + Warning( "Analysis fps (%.2f) is greater than capturing fps (%.2f)", analysis_fps, capturing_fps ); + return( 0 ); + } + else + { + return( ( 1000000 / analysis_fps ) - ( 1000000 / capturing_fps ) ); + } } void Monitor::UpdateAdaptiveSkip() { - if ( config.opt_adaptive_skip ) - { - double capturing_fps = GetFPS(); - if ( adaptive_skip && analysis_fps && ( analysis_fps < capturing_fps ) ) - { - Info( "Analysis fps (%.2f) is lower than capturing fps (%.2f), disabling adaptive skip feature", analysis_fps, capturing_fps ); - adaptive_skip = false; - } - else if ( !adaptive_skip && ( !analysis_fps || ( analysis_fps >= capturing_fps ) ) ) - { - Info( "Enabling adaptive skip feature" ); - adaptive_skip = true; - } - } - else - { - adaptive_skip = false; - } + if ( config.opt_adaptive_skip ) + { + double capturing_fps = GetFPS(); + if ( adaptive_skip && analysis_fps && ( analysis_fps < capturing_fps ) ) + { + Info( "Analysis fps (%.2f) is lower than capturing fps (%.2f), disabling adaptive skip feature", analysis_fps, capturing_fps ); + adaptive_skip = false; + } + else if ( !adaptive_skip && ( !analysis_fps || ( analysis_fps >= capturing_fps ) ) ) + { + Info( "Enabling adaptive skip feature" ); + adaptive_skip = true; + } + } + else + { + adaptive_skip = false; + } } void Monitor::ForceAlarmOn( int force_score, const char *force_cause, const char *force_text ) { - trigger_data->trigger_state = TRIGGER_ON; - trigger_data->trigger_score = force_score; - strncpy( trigger_data->trigger_cause, force_cause, sizeof(trigger_data->trigger_cause) ); - strncpy( trigger_data->trigger_text, force_text, sizeof(trigger_data->trigger_text) ); + trigger_data->trigger_state = TRIGGER_ON; + trigger_data->trigger_score = force_score; + strncpy( trigger_data->trigger_cause, force_cause, sizeof(trigger_data->trigger_cause) ); + strncpy( trigger_data->trigger_text, force_text, sizeof(trigger_data->trigger_text) ); } void Monitor::ForceAlarmOff() { - trigger_data->trigger_state = TRIGGER_OFF; + trigger_data->trigger_state = TRIGGER_OFF; } void Monitor::CancelForced() { - trigger_data->trigger_state = TRIGGER_CANCEL; + trigger_data->trigger_state = TRIGGER_CANCEL; } void Monitor::actionReload() { - shared_data->action |= RELOAD; + shared_data->action |= RELOAD; } void Monitor::actionEnable() { - shared_data->action |= RELOAD; + shared_data->action |= RELOAD; - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "update Monitors set Enabled = 1 where Id = '%d'", id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "update Monitors set Enabled = 1 where Id = '%d'", id ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } } void Monitor::actionDisable() { - shared_data->action |= RELOAD; + shared_data->action |= RELOAD; - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "update Monitors set Enabled = 0 where Id = '%d'", id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "update Monitors set Enabled = 0 where Id = '%d'", id ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } } void Monitor::actionSuspend() { - shared_data->action |= SUSPEND; + shared_data->action |= SUSPEND; } void Monitor::actionResume() { - shared_data->action |= RESUME; + shared_data->action |= RESUME; } int Monitor::actionBrightness( int p_brightness ) { - if ( purpose != CAPTURE ) - { - if ( p_brightness >= 0 ) - { - shared_data->brightness = p_brightness; - shared_data->action |= SET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & SET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to set brightness" ); - return( -1 ); - } - } - } - else - { - shared_data->action |= GET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & GET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to get brightness" ); - return( -1 ); - } - } - } - return( shared_data->brightness ); - } - return( camera->Brightness( p_brightness ) ); + if ( purpose != CAPTURE ) + { + if ( p_brightness >= 0 ) + { + shared_data->brightness = p_brightness; + shared_data->action |= SET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & SET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to set brightness" ); + return( -1 ); + } + } + } + else + { + shared_data->action |= GET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & GET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to get brightness" ); + return( -1 ); + } + } + } + return( shared_data->brightness ); + } + return( camera->Brightness( p_brightness ) ); } int Monitor::actionContrast( int p_contrast ) { - if ( purpose != CAPTURE ) - { - if ( p_contrast >= 0 ) - { - shared_data->contrast = p_contrast; - shared_data->action |= SET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & SET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to set contrast" ); - return( -1 ); - } - } - } - else - { - shared_data->action |= GET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & GET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to get contrast" ); - return( -1 ); - } - } - } - return( shared_data->contrast ); - } - return( camera->Contrast( p_contrast ) ); + if ( purpose != CAPTURE ) + { + if ( p_contrast >= 0 ) + { + shared_data->contrast = p_contrast; + shared_data->action |= SET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & SET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to set contrast" ); + return( -1 ); + } + } + } + else + { + shared_data->action |= GET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & GET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to get contrast" ); + return( -1 ); + } + } + } + return( shared_data->contrast ); + } + return( camera->Contrast( p_contrast ) ); } int Monitor::actionHue( int p_hue ) { - if ( purpose != CAPTURE ) - { - if ( p_hue >= 0 ) - { - shared_data->hue = p_hue; - shared_data->action |= SET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & SET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to set hue" ); - return( -1 ); - } - } - } - else - { - shared_data->action |= GET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & GET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to get hue" ); - return( -1 ); - } - } - } - return( shared_data->hue ); - } - return( camera->Hue( p_hue ) ); + if ( purpose != CAPTURE ) + { + if ( p_hue >= 0 ) + { + shared_data->hue = p_hue; + shared_data->action |= SET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & SET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to set hue" ); + return( -1 ); + } + } + } + else + { + shared_data->action |= GET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & GET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to get hue" ); + return( -1 ); + } + } + } + return( shared_data->hue ); + } + return( camera->Hue( p_hue ) ); } int Monitor::actionColour( int p_colour ) { - if ( purpose != CAPTURE ) - { - if ( p_colour >= 0 ) - { - shared_data->colour = p_colour; - shared_data->action |= SET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & SET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to set colour" ); - return( -1 ); - } - } - } - else - { - shared_data->action |= GET_SETTINGS; - int wait_loops = 10; - while ( shared_data->action & GET_SETTINGS ) - { - if ( wait_loops-- ) - usleep( 100000 ); - else - { - Warning( "Timed out waiting to get colour" ); - return( -1 ); - } - } - } - return( shared_data->colour ); - } - return( camera->Colour( p_colour ) ); + if ( purpose != CAPTURE ) + { + if ( p_colour >= 0 ) + { + shared_data->colour = p_colour; + shared_data->action |= SET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & SET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to set colour" ); + return( -1 ); + } + } + } + else + { + shared_data->action |= GET_SETTINGS; + int wait_loops = 10; + while ( shared_data->action & GET_SETTINGS ) + { + if ( wait_loops-- ) + usleep( 100000 ); + else + { + Warning( "Timed out waiting to get colour" ); + return( -1 ); + } + } + } + return( shared_data->colour ); + } + return( camera->Colour( p_colour ) ); } void Monitor::DumpZoneImage( const char *zone_string ) { - int exclude_id = 0; - int extra_colour = 0; - Polygon extra_zone; + int exclude_id = 0; + int extra_colour = 0; + Polygon extra_zone; - if ( zone_string ) - { - if ( !Zone::ParseZoneString( zone_string, exclude_id, extra_colour, extra_zone ) ) - { - Error( "Failed to parse zone string, ignoring" ); - } - } + if ( zone_string ) + { + if ( !Zone::ParseZoneString( zone_string, exclude_id, extra_colour, extra_zone ) ) + { + Error( "Failed to parse zone string, ignoring" ); + } + } - int index = shared_data->last_write_index; - Snapshot *snap = &image_buffer[index]; - Image *snap_image = snap->image; + int index = shared_data->last_write_index; + Snapshot *snap = &image_buffer[index]; + Image *snap_image = snap->image; - Image zone_image( *snap_image ); - if(zone_image.Colours() == ZM_COLOUR_GRAY8) { - zone_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); - } - - for( int i = 0; i < n_zones; i++ ) - { - if ( exclude_id && (!extra_colour || extra_zone.getNumCoords()) && zones[i]->Id() == exclude_id ) - continue; + Image zone_image( *snap_image ); + if(zone_image.Colours() == ZM_COLOUR_GRAY8) { + zone_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); + } + + for( int i = 0; i < n_zones; i++ ) + { + if ( exclude_id && (!extra_colour || extra_zone.getNumCoords()) && zones[i]->Id() == exclude_id ) + continue; - Rgb colour; - if ( exclude_id && !extra_zone.getNumCoords() && zones[i]->Id() == exclude_id ) - { - colour = extra_colour; - } - else - { - if ( zones[i]->IsActive() ) - { - colour = RGB_RED; - } - else if ( zones[i]->IsInclusive() ) - { - colour = RGB_ORANGE; - } - else if ( zones[i]->IsExclusive() ) - { - colour = RGB_PURPLE; - } - else if ( zones[i]->IsPreclusive() ) - { - colour = RGB_BLUE; - } - else - { - colour = RGB_WHITE; - } - } - zone_image.Fill( colour, 2, zones[i]->GetPolygon() ); - zone_image.Outline( colour, zones[i]->GetPolygon() ); - } + Rgb colour; + if ( exclude_id && !extra_zone.getNumCoords() && zones[i]->Id() == exclude_id ) + { + colour = extra_colour; + } + else + { + if ( zones[i]->IsActive() ) + { + colour = RGB_RED; + } + else if ( zones[i]->IsInclusive() ) + { + colour = RGB_ORANGE; + } + else if ( zones[i]->IsExclusive() ) + { + colour = RGB_PURPLE; + } + else if ( zones[i]->IsPreclusive() ) + { + colour = RGB_BLUE; + } + else + { + colour = RGB_WHITE; + } + } + zone_image.Fill( colour, 2, zones[i]->GetPolygon() ); + zone_image.Outline( colour, zones[i]->GetPolygon() ); + } - if ( extra_zone.getNumCoords() ) - { - zone_image.Fill( extra_colour, 2, extra_zone ); - zone_image.Outline( extra_colour, extra_zone ); - } + if ( extra_zone.getNumCoords() ) + { + zone_image.Fill( extra_colour, 2, extra_zone ); + zone_image.Outline( extra_colour, extra_zone ); + } - static char filename[PATH_MAX]; - snprintf( filename, sizeof(filename), "Zones%d.jpg", id ); - zone_image.WriteJpeg( filename ); + static char filename[PATH_MAX]; + snprintf( filename, sizeof(filename), "Zones%d.jpg", id ); + zone_image.WriteJpeg( filename ); } void Monitor::DumpImage( Image *dump_image ) const { - if ( image_count && !(image_count%10) ) - { - static char filename[PATH_MAX]; - static char new_filename[PATH_MAX]; - snprintf( filename, sizeof(filename), "Monitor%d.jpg", id ); - snprintf( new_filename, sizeof(new_filename), "Monitor%d-new.jpg", id ); - dump_image->WriteJpeg( new_filename ); - rename( new_filename, filename ); - } + if ( image_count && !(image_count%10) ) + { + static char filename[PATH_MAX]; + static char new_filename[PATH_MAX]; + snprintf( filename, sizeof(filename), "Monitor%d.jpg", id ); + snprintf( new_filename, sizeof(new_filename), "Monitor%d-new.jpg", id ); + dump_image->WriteJpeg( new_filename ); + rename( new_filename, filename ); + } } bool Monitor::CheckSignal( const Image *image ) { - static bool static_undef = true; - /* RGB24 colors */ - static uint8_t red_val; - static uint8_t green_val; - static uint8_t blue_val; - static uint8_t grayscale_val; /* 8bit grayscale color */ - static Rgb colour_val; /* RGB32 color */ - static int usedsubpixorder; + static bool static_undef = true; + /* RGB24 colors */ + static uint8_t red_val; + static uint8_t green_val; + static uint8_t blue_val; + static uint8_t grayscale_val; /* 8bit grayscale color */ + static Rgb colour_val; /* RGB32 color */ + static int usedsubpixorder; - if ( config.signal_check_points > 0 ) - { - if ( static_undef ) - { - static_undef = false; - usedsubpixorder = camera->SubpixelOrder(); - colour_val = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */ - colour_val = rgb_convert(colour_val, usedsubpixorder); - red_val = RED_VAL_BGRA(signal_check_colour); - green_val = GREEN_VAL_BGRA(signal_check_colour); - blue_val = BLUE_VAL_BGRA(signal_check_colour); - grayscale_val = signal_check_colour & 0xff; /* Clear all bytes but lowest byte */ - } + if ( config.signal_check_points > 0 ) + { + if ( static_undef ) + { + static_undef = false; + usedsubpixorder = camera->SubpixelOrder(); + colour_val = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */ + colour_val = rgb_convert(colour_val, usedsubpixorder); + red_val = RED_VAL_BGRA(signal_check_colour); + green_val = GREEN_VAL_BGRA(signal_check_colour); + blue_val = BLUE_VAL_BGRA(signal_check_colour); + grayscale_val = signal_check_colour & 0xff; /* Clear all bytes but lowest byte */ + } - const uint8_t *buffer = image->Buffer(); - int pixels = image->Pixels(); - int width = image->Width(); - int colours = image->Colours(); + const uint8_t *buffer = image->Buffer(); + int pixels = image->Pixels(); + int width = image->Width(); + int colours = image->Colours(); - int index = 0; - for ( int i = 0; i < config.signal_check_points; i++ ) - { - while( true ) - { - index = (int)(((long long)rand()*(long long)(pixels-1))/RAND_MAX); - if ( !config.timestamp_on_capture || !label_format[0] ) - break; - // Avoid sampling the rows with timestamp in - if ( index < (label_coord.Y()*width) || index >= (label_coord.Y()+Image::LINE_HEIGHT)*width ) - break; - } - + int index = 0; + for ( int i = 0; i < config.signal_check_points; i++ ) + { + while( true ) + { + index = (int)(((long long)rand()*(long long)(pixels-1))/RAND_MAX); + if ( !config.timestamp_on_capture || !label_format[0] ) + break; + // Avoid sampling the rows with timestamp in + if ( index < (label_coord.Y()*width) || index >= (label_coord.Y()+Image::LINE_HEIGHT)*width ) + break; + } + if(colours == ZM_COLOUR_GRAY8) { if ( *(buffer+index) != grayscale_val ) return true; @@ -1280,844 +1244,845 @@ bool Monitor::CheckSignal( const Image *image ) return true; } } - - } - return( false ); - } - return( true ); + + } + return( false ); + } + return( true ); } bool Monitor::Analyse() { - if ( shared_data->last_read_index == shared_data->last_write_index ) - { - return( false ); - } + if ( shared_data->last_read_index == shared_data->last_write_index ) + { + return( false ); + } - struct timeval now; - gettimeofday( &now, NULL ); + struct timeval now; + gettimeofday( &now, NULL ); - if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) - { - fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); - Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps ); - last_fps_time = now.tv_sec; - } + if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) + { + fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); + Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps ); + last_fps_time = now.tv_sec; + } - int index; - if ( adaptive_skip ) - { - int read_margin = shared_data->last_read_index - shared_data->last_write_index; - if ( read_margin < 0 ) read_margin += image_buffer_count; + int index; + if ( adaptive_skip ) + { + int read_margin = shared_data->last_read_index - shared_data->last_write_index; + if ( read_margin < 0 ) read_margin += image_buffer_count; - int step = 1; - if ( read_margin > 0 ) - { - step = (9*image_buffer_count)/(5*read_margin); - } + int step = 1; + if ( read_margin > 0 ) + { + step = (9*image_buffer_count)/(5*read_margin); + } - int pending_frames = shared_data->last_write_index - shared_data->last_read_index; - if ( pending_frames < 0 ) pending_frames += image_buffer_count; + int pending_frames = shared_data->last_write_index - shared_data->last_read_index; + if ( pending_frames < 0 ) pending_frames += image_buffer_count; - Debug( 4, "RI:%d, WI: %d, PF = %d, RM = %d, Step = %d", shared_data->last_read_index, shared_data->last_write_index, pending_frames, read_margin, step ); - if ( step <= pending_frames ) - { - index = (shared_data->last_read_index+step)%image_buffer_count; - } - else - { - if ( pending_frames ) - { - Warning( "Approaching buffer overrun, consider slowing capture, simplifying analysis or increasing ring buffer size" ); - } - index = shared_data->last_write_index%image_buffer_count; - } - } - else - { - index = shared_data->last_write_index%image_buffer_count; - } + Debug( 4, "RI:%d, WI: %d, PF = %d, RM = %d, Step = %d", shared_data->last_read_index, shared_data->last_write_index, pending_frames, read_margin, step ); + if ( step <= pending_frames ) + { + index = (shared_data->last_read_index+step)%image_buffer_count; + } + else + { + if ( pending_frames ) + { + Warning( "Approaching buffer overrun, consider slowing capture, simplifying analysis or increasing ring buffer size" ); + } + index = shared_data->last_write_index%image_buffer_count; + } + } + else + { + index = shared_data->last_write_index%image_buffer_count; + } - Snapshot *snap = &image_buffer[index]; - struct timeval *timestamp = snap->timestamp; - Image *snap_image = snap->image; + Snapshot *snap = &image_buffer[index]; + struct timeval *timestamp = snap->timestamp; + Image *snap_image = snap->image; - if ( shared_data->action ) - { - if ( shared_data->action & RELOAD ) - { - Info( "Received reload indication at count %d", image_count ); - shared_data->action &= ~RELOAD; - Reload(); - } - if ( shared_data->action & SUSPEND ) - { - if ( Active() ) - { - Info( "Received suspend indication at count %d", image_count ); - shared_data->active = false; - //closeEvent(); - } - if ( config.max_suspend_time ) - { - auto_resume_time = now.tv_sec + config.max_suspend_time; - } - shared_data->action &= ~SUSPEND; - } - if ( shared_data->action & RESUME ) - { - if ( Enabled() && !Active() ) - { - Info( "Received resume indication at count %d", image_count ); - shared_data->active = true; - ref_image = *snap_image; - ready_count = image_count+(warmup_count/2); - shared_data->alarm_x = shared_data->alarm_y = -1; - } - shared_data->action &= ~RESUME; - } - } - if ( auto_resume_time && (now.tv_sec >= auto_resume_time) ) - { - Info( "Auto resuming at count %d", image_count ); - shared_data->active = true; - ref_image = *snap_image; - ready_count = image_count+(warmup_count/2); - auto_resume_time = 0; - } + if ( shared_data->action ) + { + if ( shared_data->action & RELOAD ) + { + Info( "Received reload indication at count %d", image_count ); + shared_data->action &= ~RELOAD; + Reload(); + } + if ( shared_data->action & SUSPEND ) + { + if ( Active() ) + { + Info( "Received suspend indication at count %d", image_count ); + shared_data->active = false; + //closeEvent(); + } + if ( config.max_suspend_time ) + { + auto_resume_time = now.tv_sec + config.max_suspend_time; + } + shared_data->action &= ~SUSPEND; + } + if ( shared_data->action & RESUME ) + { + if ( Enabled() && !Active() ) + { + Info( "Received resume indication at count %d", image_count ); + shared_data->active = true; + ref_image = *snap_image; + ready_count = image_count+(warmup_count/2); + shared_data->alarm_x = shared_data->alarm_y = -1; + } + shared_data->action &= ~RESUME; + } + } + if ( auto_resume_time && (now.tv_sec >= auto_resume_time) ) + { + Info( "Auto resuming at count %d", image_count ); + shared_data->active = true; + ref_image = *snap_image; + ready_count = image_count+(warmup_count/2); + auto_resume_time = 0; + } - static bool static_undef = true; - static int last_section_mod = 0; - static bool last_signal; + static bool static_undef = true; + static int last_section_mod = 0; + static bool last_signal; - if ( static_undef ) - { - static_undef = false; - timestamps = new struct timeval *[pre_event_count]; - images = new Image *[pre_event_count]; - last_signal = shared_data->signal; - } + if ( static_undef ) + { + static_undef = false; + timestamps = new struct timeval *[pre_event_count]; + images = new Image *[pre_event_count]; + last_signal = shared_data->signal; + } - if ( Enabled() ) - { - bool signal = shared_data->signal; - bool signal_change = (signal != last_signal); - - //Set video recording flag for event start constructor and easy reference in code - bool videoRecording = ((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()); - - if ( trigger_data->trigger_state != TRIGGER_OFF ) - { - unsigned int score = 0; - if ( Ready() ) - { - std::string cause; - Event::StringSetMap noteSetMap; + if ( Enabled() ) + { + bool signal = shared_data->signal; + bool signal_change = (signal != last_signal); + + //Set video recording flag for event start constructor and easy reference in code + bool videoRecording = ((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()); + + if ( trigger_data->trigger_state != TRIGGER_OFF ) + { + unsigned int score = 0; + if ( Ready() ) + { + std::string cause; + Event::StringSetMap noteSetMap; - if ( trigger_data->trigger_state == TRIGGER_ON ) - { - score += trigger_data->trigger_score; - if ( !event ) - { - if ( cause.length() ) - cause += ", "; - cause += trigger_data->trigger_cause; - } - Event::StringSet noteSet; - noteSet.insert( trigger_data->trigger_text ); - noteSetMap[trigger_data->trigger_cause] = noteSet; - } - if ( signal_change ) - { - const char *signalText; - if ( !signal ) - signalText = "Lost"; - else - { - signalText = "Reacquired"; - score += 100; - } - Warning( "%s: %s", SIGNAL_CAUSE, signalText ); - if ( event && !signal ) - { - Info( "%s: %03d - Closing event %d, signal loss", name, image_count, event->Id() ); - closeEvent(); - last_section_mod = 0; - } - if ( !event ) - { - if ( cause.length() ) - cause += ", "; - cause += SIGNAL_CAUSE; - } - Event::StringSet noteSet; - noteSet.insert( signalText ); - noteSetMap[SIGNAL_CAUSE] = noteSet; - shared_data->state = state = IDLE; - shared_data->active = signal; - ref_image = *snap_image; - } - else if ( signal && Active() && (function == MODECT || function == MOCORD) ) - { - Event::StringSet zoneSet; - int motion_score = last_motion_score; - if ( !(image_count % (motion_frame_skip+1) ) ) - { - // Get new score. - motion_score = last_motion_score = DetectMotion( *snap_image, zoneSet ); - } - //int motion_score = DetectBlack( *snap_image, zoneSet ); - if ( motion_score ) - { - if ( !event ) - { - score += motion_score; - if ( cause.length() ) - cause += ", "; - cause += MOTION_CAUSE; - } - else - { - score += motion_score; - } - noteSetMap[MOTION_CAUSE] = zoneSet; + if ( trigger_data->trigger_state == TRIGGER_ON ) + { + score += trigger_data->trigger_score; + if ( !event ) + { + if ( cause.length() ) + cause += ", "; + cause += trigger_data->trigger_cause; + } + Event::StringSet noteSet; + noteSet.insert( trigger_data->trigger_text ); + noteSetMap[trigger_data->trigger_cause] = noteSet; + } + if ( signal_change ) + { + const char *signalText; + if ( !signal ) + signalText = "Lost"; + else + { + signalText = "Reacquired"; + score += 100; + } + Warning( "%s: %s", SIGNAL_CAUSE, signalText ); + if ( event && !signal ) + { + Info( "%s: %03d - Closing event %d, signal loss", name, image_count, event->Id() ); + closeEvent(); + last_section_mod = 0; + } + if ( !event ) + { + if ( cause.length() ) + cause += ", "; + cause += SIGNAL_CAUSE; + } + Event::StringSet noteSet; + noteSet.insert( signalText ); + noteSetMap[SIGNAL_CAUSE] = noteSet; + shared_data->state = state = IDLE; + shared_data->active = signal; + ref_image = *snap_image; + } + else if ( signal && Active() && (function == MODECT || function == MOCORD) ) + { + Event::StringSet zoneSet; + int motion_score = last_motion_score; + if ( !(image_count % (motion_frame_skip+1) ) ) + { + // Get new score. + motion_score = last_motion_score = DetectMotion( *snap_image, zoneSet ); + } + //int motion_score = DetectBlack( *snap_image, zoneSet ); + if ( motion_score ) + { + if ( !event ) + { + score += motion_score; + if ( cause.length() ) + cause += ", "; + cause += MOTION_CAUSE; + } + else + { + score += motion_score; + } + noteSetMap[MOTION_CAUSE] = zoneSet; - } - shared_data->active = signal; - } - if ( (!signal_change && signal) && n_linked_monitors > 0 ) - { - bool first_link = true; - Event::StringSet noteSet; - for ( int i = 0; i < n_linked_monitors; i++ ) - { - if ( linked_monitors[i]->isConnected() ) - { - if ( linked_monitors[i]->hasAlarmed() ) - { - if ( !event ) - { - if ( first_link ) - { - if ( cause.length() ) - cause += ", "; - cause += LINKED_CAUSE; - first_link = false; - } - } - noteSet.insert( linked_monitors[i]->Name() ); - score += 50; - } - } - else - { - linked_monitors[i]->connect(); - } - } - if ( noteSet.size() > 0 ) - noteSetMap[LINKED_CAUSE] = noteSet; - } - - //TODO: What happens is the event closes and sets recording to false then recording to true again so quickly that our capture daemon never picks it up. Maybe need a refresh flag? - if ( (!signal_change && signal) && (function == RECORD || function == MOCORD) ) - { - if ( event ) - { - //TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here?? - snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); - - int section_mod = timestamp->tv_sec%section_length; - if ( section_mod < last_section_mod ) - { - if ( state == IDLE || state == TAPE || event_close_mode == CLOSE_TIME ) - { - if ( state == TAPE ) - { - shared_data->state = state = IDLE; - Info( "%s: %03d - Closing event %d, section end", name, image_count, event->Id() ) - } - else - Info( "%s: %03d - Closing event %d, section end forced ", name, image_count, event->Id() ); - closeEvent(); - last_section_mod = 0; - } - } - else - { - last_section_mod = section_mod; - } - } - if ( !event ) - { + } + shared_data->active = signal; + } + if ( (!signal_change && signal) && n_linked_monitors > 0 ) + { + bool first_link = true; + Event::StringSet noteSet; + for ( int i = 0; i < n_linked_monitors; i++ ) + { + if ( linked_monitors[i]->isConnected() ) + { + if ( linked_monitors[i]->hasAlarmed() ) + { + if ( !event ) + { + if ( first_link ) + { + if ( cause.length() ) + cause += ", "; + cause += LINKED_CAUSE; + first_link = false; + } + } + noteSet.insert( linked_monitors[i]->Name() ); + score += 50; + } + } + else + { + linked_monitors[i]->connect(); + } + } + if ( noteSet.size() > 0 ) + noteSetMap[LINKED_CAUSE] = noteSet; + } + + //TODO: What happens is the event closes and sets recording to false then recording to true again so quickly that our capture daemon never picks it up. Maybe need a refresh flag? + if ( (!signal_change && signal) && (function == RECORD || function == MOCORD) ) + { + if ( event ) + { + //TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here?? + snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); + + int section_mod = timestamp->tv_sec%section_length; + if ( section_mod < last_section_mod ) + { + if ( state == IDLE || state == TAPE || event_close_mode == CLOSE_TIME ) + { + if ( state == TAPE ) + { + shared_data->state = state = IDLE; + Info( "%s: %03d - Closing event %d, section end", name, image_count, event->Id() ) + } + else + Info( "%s: %03d - Closing event %d, section end forced ", name, image_count, event->Id() ); + closeEvent(); + last_section_mod = 0; + } + } + else + { + last_section_mod = section_mod; + } + } + if ( !event ) + { - // Create event - event = new Event( this, *timestamp, "Continuous", noteSetMap, videoRecording ); - shared_data->last_event = event->Id(); - //set up video store data - snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); - video_store_data->recording = true; - - Info( "%s: %03d - Opening new event %d, section start", name, image_count, event->Id() ); + // Create event + event = new Event( this, *timestamp, "Continuous", noteSetMap, videoRecording ); + shared_data->last_event = event->Id(); + //set up video store data + snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); + video_store_data->recording = true; + + Info( "%s: %03d - Opening new event %d, section start", name, image_count, event->Id() ); - /* To prevent cancelling out an existing alert\prealarm\alarm state */ - if ( state == IDLE ) - { - shared_data->state = state = TAPE; - } + /* To prevent cancelling out an existing alert\prealarm\alarm state */ + if ( state == IDLE ) + { + shared_data->state = state = TAPE; + } - //if ( config.overlap_timed_events ) - if ( false ) - { - int pre_index; - int pre_event_images = pre_event_count; + //if ( config.overlap_timed_events ) + if ( false ) + { + int pre_index; + int pre_event_images = pre_event_count; - if ( analysis_fps ) - { - // If analysis fps is set, - // compute the index for pre event images in the dedicated buffer - pre_index = image_count%pre_event_buffer_count; + if ( analysis_fps ) + { + // If analysis fps is set, + // compute the index for pre event images in the dedicated buffer + pre_index = image_count%pre_event_buffer_count; - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) - { - pre_index = (pre_index + 1)%pre_event_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } - } - else - { - // If analysis fps is not set (analysis performed at capturing framerate), - // compute the index for pre event images in the capturing buffer - pre_index = ((index + image_buffer_count) - pre_event_count)%image_buffer_count; + // Seek forward the next filled slot in to the buffer (oldest data) + // from the current position + while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) + { + pre_index = (pre_index + 1)%pre_event_buffer_count; + // Slot is empty, removing image from counter + pre_event_images--; + } + } + else + { + // If analysis fps is not set (analysis performed at capturing framerate), + // compute the index for pre event images in the capturing buffer + pre_index = ((index + image_buffer_count) - pre_event_count)%image_buffer_count; - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - while ( pre_event_images && !image_buffer[pre_index].timestamp->tv_sec ) - { - pre_index = (pre_index + 1)%image_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } - } + // Seek forward the next filled slot in to the buffer (oldest data) + // from the current position + while ( pre_event_images && !image_buffer[pre_index].timestamp->tv_sec ) + { + pre_index = (pre_index + 1)%image_buffer_count; + // Slot is empty, removing image from counter + pre_event_images--; + } + } - if ( pre_event_images ) - { - if ( analysis_fps ) - for ( int i = 0; i < pre_event_images; i++ ) - { - timestamps[i] = pre_event_buffer[pre_index].timestamp; - images[i] = pre_event_buffer[pre_index].image; - pre_index = (pre_index + 1)%pre_event_buffer_count; - } - else - for ( int i = 0; i < pre_event_images; i++ ) - { - timestamps[i] = image_buffer[pre_index].timestamp; - images[i] = image_buffer[pre_index].image; - pre_index = (pre_index + 1)%image_buffer_count; - } + if ( pre_event_images ) + { + if ( analysis_fps ) + for ( int i = 0; i < pre_event_images; i++ ) + { + timestamps[i] = pre_event_buffer[pre_index].timestamp; + images[i] = pre_event_buffer[pre_index].image; + pre_index = (pre_index + 1)%pre_event_buffer_count; + } + else + for ( int i = 0; i < pre_event_images; i++ ) + { + timestamps[i] = image_buffer[pre_index].timestamp; + images[i] = image_buffer[pre_index].image; + pre_index = (pre_index + 1)%image_buffer_count; + } - event->AddFrames( pre_event_images, images, timestamps ); - } - } - } - } - if ( score ) - { - if ( (state == IDLE || state == TAPE || state == PREALARM ) ) - { - if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) - { - Info( "%s: %03d - Gone into alarm state", name, image_count ); - shared_data->state = state = ALARM; - if ( signal_change || (function != MOCORD && state != ALERT) ) - { - int pre_index; - int pre_event_images = pre_event_count; + event->AddFrames( pre_event_images, images, timestamps ); + } + } + } + } + if ( score ) + { + if ( (state == IDLE || state == TAPE || state == PREALARM ) ) + { + if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) + { + Info( "%s: %03d - Gone into alarm state", name, image_count ); + shared_data->state = state = ALARM; + if ( signal_change || (function != MOCORD && state != ALERT) ) + { + int pre_index; + int pre_event_images = pre_event_count; - if ( analysis_fps ) - { - // If analysis fps is set, - // compute the index for pre event images in the dedicated buffer - pre_index = image_count%pre_event_buffer_count; + if ( analysis_fps ) + { + // If analysis fps is set, + // compute the index for pre event images in the dedicated buffer + pre_index = image_count%pre_event_buffer_count; - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) - { - pre_index = (pre_index + 1)%pre_event_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } + // Seek forward the next filled slot in to the buffer (oldest data) + // from the current position + while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) + { + pre_index = (pre_index + 1)%pre_event_buffer_count; + // Slot is empty, removing image from counter + pre_event_images--; + } - event = new Event( this, *(pre_event_buffer[pre_index].timestamp), cause, noteSetMap ); - } - else - { - // If analysis fps is not set (analysis performed at capturing framerate), - // compute the index for pre event images in the capturing buffer - if ( alarm_frame_count > 1 ) - pre_index = ((index + image_buffer_count) - ((alarm_frame_count - 1) + pre_event_count))%image_buffer_count; - else - pre_index = ((index + image_buffer_count) - pre_event_count)%image_buffer_count; + event = new Event( this, *(pre_event_buffer[pre_index].timestamp), cause, noteSetMap ); + } + else + { + // If analysis fps is not set (analysis performed at capturing framerate), + // compute the index for pre event images in the capturing buffer + if ( alarm_frame_count > 1 ) + pre_index = ((index + image_buffer_count) - ((alarm_frame_count - 1) + pre_event_count))%image_buffer_count; + else + pre_index = ((index + image_buffer_count) - pre_event_count)%image_buffer_count; - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - while ( pre_event_images && !image_buffer[pre_index].timestamp->tv_sec ) - { - pre_index = (pre_index + 1)%image_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } + // Seek forward the next filled slot in to the buffer (oldest data) + // from the current position + while ( pre_event_images && !image_buffer[pre_index].timestamp->tv_sec ) + { + pre_index = (pre_index + 1)%image_buffer_count; + // Slot is empty, removing image from counter + pre_event_images--; + } - event = new Event( this, *(image_buffer[pre_index].timestamp), cause, noteSetMap ); - } - shared_data->last_event = event->Id(); - //set up video store data - snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); - video_store_data->recording = true; + event = new Event( this, *(image_buffer[pre_index].timestamp), cause, noteSetMap ); + } + shared_data->last_event = event->Id(); + //set up video store data + snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); + video_store_data->recording = true; - Info( "%s: %03d - Opening new event %d, alarm start", name, image_count, event->Id() ); + Info( "%s: %03d - Opening new event %d, alarm start", name, image_count, event->Id() ); - if ( pre_event_images ) - { - if ( analysis_fps ) - for ( int i = 0; i < pre_event_images; i++ ) - { - timestamps[i] = pre_event_buffer[pre_index].timestamp; - images[i] = pre_event_buffer[pre_index].image; - pre_index = (pre_index + 1)%pre_event_buffer_count; - } - else - for ( int i = 0; i < pre_event_images; i++ ) - { - timestamps[i] = image_buffer[pre_index].timestamp; - images[i] = image_buffer[pre_index].image; - pre_index = (pre_index + 1)%image_buffer_count; - } + if ( pre_event_images ) + { + if ( analysis_fps ) + for ( int i = 0; i < pre_event_images; i++ ) + { + timestamps[i] = pre_event_buffer[pre_index].timestamp; + images[i] = pre_event_buffer[pre_index].image; + pre_index = (pre_index + 1)%pre_event_buffer_count; + } + else + for ( int i = 0; i < pre_event_images; i++ ) + { + timestamps[i] = image_buffer[pre_index].timestamp; + images[i] = image_buffer[pre_index].image; + pre_index = (pre_index + 1)%image_buffer_count; + } - event->AddFrames( pre_event_images, images, timestamps ); - } - if ( alarm_frame_count ) - { - event->SavePreAlarmFrames(); - } - } - } - else if ( state != PREALARM ) - { - Info( "%s: %03d - Gone into prealarm state", name, image_count ); - shared_data->state = state = PREALARM; - } - } - else if ( state == ALERT ) - { - Info( "%s: %03d - Gone back into alarm state", name, image_count ); - shared_data->state = state = ALARM; - } - last_alarm_count = image_count; - } - else - { - if ( state == ALARM ) - { - Info( "%s: %03d - Gone into alert state", name, image_count ); - shared_data->state = state = ALERT; - } - else if ( state == ALERT ) - { - if ( image_count-last_alarm_count > post_event_count ) - { - Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); - //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) - if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) - { - shared_data->state = state = IDLE; - Info( "%s: %03d - Closing event %d, alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); - closeEvent(); - } - else - { - shared_data->state = state = TAPE; - } - } - } - if ( state == PREALARM ) - { - if ( function != MOCORD ) - { - shared_data->state = state = IDLE; - } - else - { - shared_data->state = state = TAPE; - } - } - if ( Event::PreAlarmCount() ) - Event::EmptyPreAlarmFrames(); - } - if ( state != IDLE ) - { - if ( state == PREALARM || state == ALARM ) - { - if ( config.create_analysis_images ) - { - bool got_anal_image = false; + event->AddFrames( pre_event_images, images, timestamps ); + } + if ( alarm_frame_count ) + { + event->SavePreAlarmFrames(); + } + } + } + else if ( state != PREALARM ) + { + Info( "%s: %03d - Gone into prealarm state", name, image_count ); + shared_data->state = state = PREALARM; + } + } + else if ( state == ALERT ) + { + Info( "%s: %03d - Gone back into alarm state", name, image_count ); + shared_data->state = state = ALARM; + } + last_alarm_count = image_count; + } + else + { + if ( state == ALARM ) + { + Info( "%s: %03d - Gone into alert state", name, image_count ); + shared_data->state = state = ALERT; + } + else if ( state == ALERT ) + { + if ( image_count-last_alarm_count > post_event_count ) + { + Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); + //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) + if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) + { + shared_data->state = state = IDLE; + Info( "%s: %03d - Closing event %d, alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); + closeEvent(); + } + else + { + shared_data->state = state = TAPE; + } + } + } + if ( state == PREALARM ) + { + if ( function != MOCORD ) + { + shared_data->state = state = IDLE; + } + else + { + shared_data->state = state = TAPE; + } + } + if ( Event::PreAlarmCount() ) + Event::EmptyPreAlarmFrames(); + } + if ( state != IDLE ) + { + if ( state == PREALARM || state == ALARM ) + { + if ( config.create_analysis_images ) + { + bool got_anal_image = false; alarm_image.Assign( *snap_image ); - for( int i = 0; i < n_zones; i++ ) - { - if ( zones[i]->Alarmed() ) - { - if ( zones[i]->AlarmImage() ) - { - alarm_image.Overlay( *(zones[i]->AlarmImage()) ); - got_anal_image = true; - } - if ( config.record_event_stats && state == ALARM ) - { - zones[i]->RecordStats( event ); - } - } - } - if ( got_anal_image ) - { - if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score, &alarm_image ); - else - event->AddFrame( snap_image, *timestamp, score, &alarm_image ); - } - else - { - if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score ); - else - event->AddFrame( snap_image, *timestamp, score ); - } - } - else - { - for( int i = 0; i < n_zones; i++ ) - { - if ( zones[i]->Alarmed() ) - { - if ( config.record_event_stats && state == ALARM ) - { - zones[i]->RecordStats( event ); - } - } - } - if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score ); - else - event->AddFrame( snap_image, *timestamp, score ); - } - if ( event && noteSetMap.size() > 0 ) - event->updateNotes( noteSetMap ); - } - else if ( state == ALERT ) - { - event->AddFrame( snap_image, *timestamp ); - if ( noteSetMap.size() > 0 ) - event->updateNotes( noteSetMap ); - } - else if ( state == TAPE ) - { - //Video Storage: activate only for supported cameras. Event::AddFrame knows whether or not we are recording video and saves frames accordingly - if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()) - { - video_store_data->recording = true; - } - if ( !(image_count%(frame_skip+1)) ) - { - if ( config.bulk_frame_interval > 1 ) - { - event->AddFrame( snap_image, *timestamp, (event->Frames()AddFrame( snap_image, *timestamp ); - } - } - } - } - } - } - else - { - if ( event ) - { - Info( "%s: %03d - Closing event %d, trigger off", name, image_count, event->Id() ); - closeEvent(); - } - shared_data->state = state = IDLE; - last_section_mod = 0; - } - if ( (!signal_change && signal) && (function == MODECT || function == MOCORD) ) - { - if ( state == ALARM ) { - ref_image.Blend( *snap_image, alarm_ref_blend_perc ); - } else { - ref_image.Blend( *snap_image, ref_blend_perc ); - } - } - last_signal = signal; - } + for( int i = 0; i < n_zones; i++ ) + { + if ( zones[i]->Alarmed() ) + { + if ( zones[i]->AlarmImage() ) + { + alarm_image.Overlay( *(zones[i]->AlarmImage()) ); + got_anal_image = true; + } + if ( config.record_event_stats && state == ALARM ) + { + zones[i]->RecordStats( event ); + } + } + } + if ( got_anal_image ) + { + if ( state == PREALARM ) + Event::AddPreAlarmFrame( snap_image, *timestamp, score, &alarm_image ); + else + event->AddFrame( snap_image, *timestamp, score, &alarm_image ); + } + else + { + if ( state == PREALARM ) + Event::AddPreAlarmFrame( snap_image, *timestamp, score ); + else + event->AddFrame( snap_image, *timestamp, score ); + } + } + else + { + for( int i = 0; i < n_zones; i++ ) + { + if ( zones[i]->Alarmed() ) + { + if ( config.record_event_stats && state == ALARM ) + { + zones[i]->RecordStats( event ); + } + } + } + if ( state == PREALARM ) + Event::AddPreAlarmFrame( snap_image, *timestamp, score ); + else + event->AddFrame( snap_image, *timestamp, score ); + } + if ( event && noteSetMap.size() > 0 ) + event->updateNotes( noteSetMap ); + } + else if ( state == ALERT ) + { + event->AddFrame( snap_image, *timestamp ); + if ( noteSetMap.size() > 0 ) + event->updateNotes( noteSetMap ); + } + else if ( state == TAPE ) + { + //Video Storage: activate only for supported cameras. Event::AddFrame knows whether or not we are recording video and saves frames accordingly + if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()) + { + video_store_data->recording = true; + } + if ( !(image_count%(frame_skip+1)) ) + { + if ( config.bulk_frame_interval > 1 ) + { + event->AddFrame( snap_image, *timestamp, (event->Frames()AddFrame( snap_image, *timestamp ); + } + } + } + } + } + } + else + { + if ( event ) + { + Info( "%s: %03d - Closing event %d, trigger off", name, image_count, event->Id() ); + closeEvent(); + } + shared_data->state = state = IDLE; + last_section_mod = 0; + } + if ( (!signal_change && signal) && (function == MODECT || function == MOCORD) ) + { + if ( state == ALARM ) { + ref_image.Blend( *snap_image, alarm_ref_blend_perc ); + } else { + ref_image.Blend( *snap_image, ref_blend_perc ); + } + } + last_signal = signal; + } - shared_data->last_read_index = index%image_buffer_count; - //shared_data->last_read_time = image_buffer[index].timestamp->tv_sec; - shared_data->last_read_time = now.tv_sec; + shared_data->last_read_index = index%image_buffer_count; + //shared_data->last_read_time = image_buffer[index].timestamp->tv_sec; + shared_data->last_read_time = now.tv_sec; - if ( analysis_fps ) - { - // If analysis fps is set, add analysed image to dedicated pre event buffer - int pre_index = image_count%pre_event_buffer_count; - pre_event_buffer[pre_index].image->Assign(*snap->image); - memcpy( pre_event_buffer[pre_index].timestamp, snap->timestamp, sizeof(struct timeval) ); - } + if ( analysis_fps ) + { + // If analysis fps is set, add analysed image to dedicated pre event buffer + int pre_index = image_count%pre_event_buffer_count; + pre_event_buffer[pre_index].image->Assign(*snap->image); + memcpy( pre_event_buffer[pre_index].timestamp, snap->timestamp, sizeof(struct timeval) ); + } - image_count++; + image_count++; - return( true ); + return( true ); } void Monitor::Reload() { - Debug( 1, "Reloading monitor %s", name ); + Debug( 1, "Reloading monitor %s", name ); - if ( event ) - Info( "%s: %03d - Closing event %d, reloading", name, image_count, event->Id() ); + if ( event ) + Info( "%s: %03d - Closing event %d, reloading", name, image_count, event->Id() ); - closeEvent(); + closeEvent(); - static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id ); + static char sql[ZM_SQL_MED_BUFSIZ]; + // This seems to have fallen out of date. + snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) - { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - int n_monitors = mysql_num_rows( result ); - if ( n_monitors != 1 ) - { - Error( "Bogus number of monitors, %d, returned. Can't reload", n_monitors ); - return; - } + MYSQL_RES *result = mysql_store_result( &dbconn ); + if ( !result ) + { + Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + int n_monitors = mysql_num_rows( result ); + if ( n_monitors != 1 ) + { + Error( "Bogus number of monitors, %d, returned. Can't reload", n_monitors ); + return; + } - if ( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) - { - int index = 0; - function = (Function)atoi(dbrow[index++]); - enabled = atoi(dbrow[index++]); - const char *p_linked_monitors = dbrow[index++]; - strncpy( event_prefix, dbrow[index++], sizeof(event_prefix) ); - strncpy( label_format, dbrow[index++], sizeof(label_format) ); - label_coord = Coord( atoi(dbrow[index]), atoi(dbrow[index+1]) ); index += 2; - label_size = atoi(dbrow[index++]); - warmup_count = atoi(dbrow[index++]); - pre_event_count = atoi(dbrow[index++]); - post_event_count = atoi(dbrow[index++]); - alarm_frame_count = atoi(dbrow[index++]); - section_length = atoi(dbrow[index++]); - frame_skip = atoi(dbrow[index++]); - motion_frame_skip = atoi(dbrow[index++]); - analysis_fps = dbrow[index] ? strtod(dbrow[index], NULL) : 0; index++; - analysis_update_delay = strtoul(dbrow[index++], NULL, 0); - capture_delay = (dbrow[index]&&atof(dbrow[index])>0.0)?int(DT_PREC_3/atof(dbrow[index])):0; index++; - alarm_capture_delay = (dbrow[index]&&atof(dbrow[index])>0.0)?int(DT_PREC_3/atof(dbrow[index])):0; index++; - fps_report_interval = atoi(dbrow[index++]); - ref_blend_perc = atoi(dbrow[index++]); - alarm_ref_blend_perc = atoi(dbrow[index++]); - track_motion = atoi(dbrow[index++]); - + if ( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) + { + int index = 0; + function = (Function)atoi(dbrow[index++]); + enabled = atoi(dbrow[index++]); + const char *p_linked_monitors = dbrow[index++]; + strncpy( event_prefix, dbrow[index++], sizeof(event_prefix) ); + strncpy( label_format, dbrow[index++], sizeof(label_format) ); + label_coord = Coord( atoi(dbrow[index]), atoi(dbrow[index+1]) ); index += 2; + label_size = atoi(dbrow[index++]); + warmup_count = atoi(dbrow[index++]); + pre_event_count = atoi(dbrow[index++]); + post_event_count = atoi(dbrow[index++]); + alarm_frame_count = atoi(dbrow[index++]); + section_length = atoi(dbrow[index++]); + frame_skip = atoi(dbrow[index++]); + motion_frame_skip = atoi(dbrow[index++]); + analysis_fps = dbrow[index] ? strtod(dbrow[index], NULL) : 0; index++; + analysis_update_delay = strtoul(dbrow[index++], NULL, 0); + capture_delay = (dbrow[index]&&atof(dbrow[index])>0.0)?int(DT_PREC_3/atof(dbrow[index])):0; index++; + alarm_capture_delay = (dbrow[index]&&atof(dbrow[index])>0.0)?int(DT_PREC_3/atof(dbrow[index])):0; index++; + fps_report_interval = atoi(dbrow[index++]); + ref_blend_perc = atoi(dbrow[index++]); + alarm_ref_blend_perc = atoi(dbrow[index++]); + track_motion = atoi(dbrow[index++]); + - if ( dbrow[index][0] == '#' ) - signal_check_colour = strtol(dbrow[index]+1,0,16); - else - signal_check_colour = strtol(dbrow[index],0,16); - index++; + if ( dbrow[index][0] == '#' ) + signal_check_colour = strtol(dbrow[index]+1,0,16); + else + signal_check_colour = strtol(dbrow[index],0,16); + index++; - shared_data->state = state = IDLE; - shared_data->alarm_x = shared_data->alarm_y = -1; - if ( enabled ) - shared_data->active = true; - ready_count = image_count+warmup_count; + shared_data->state = state = IDLE; + shared_data->alarm_x = shared_data->alarm_y = -1; + if ( enabled ) + shared_data->active = true; + ready_count = image_count+warmup_count; - ReloadLinkedMonitors( p_linked_monitors ); - } - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - mysql_free_result( result ); + ReloadLinkedMonitors( p_linked_monitors ); + } + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + mysql_free_result( result ); - ReloadZones(); + ReloadZones(); } void Monitor::ReloadZones() { - Debug( 1, "Reloading zones for monitor %s", name ); - for( int i = 0; i < n_zones; i++ ) - { - delete zones[i]; - } - delete[] zones; - zones = 0; - n_zones = Zone::Load( this, zones ); - //DumpZoneImage(); + Debug( 1, "Reloading zones for monitor %s", name ); + for( int i = 0; i < n_zones; i++ ) + { + delete zones[i]; + } + delete[] zones; + zones = 0; + n_zones = Zone::Load( this, zones ); + //DumpZoneImage(); } void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { - Debug( 1, "Reloading linked monitors for monitor %s, '%s'", name, p_linked_monitors ); - if ( n_linked_monitors ) - { - for( int i = 0; i < n_linked_monitors; i++ ) - { - delete linked_monitors[i]; - } - delete[] linked_monitors; - linked_monitors = 0; - } + Debug( 1, "Reloading linked monitors for monitor %s, '%s'", name, p_linked_monitors ); + if ( n_linked_monitors ) + { + for( int i = 0; i < n_linked_monitors; i++ ) + { + delete linked_monitors[i]; + } + delete[] linked_monitors; + linked_monitors = 0; + } - n_linked_monitors = 0; - if ( p_linked_monitors ) - { - int n_link_ids = 0; - unsigned int link_ids[256]; + n_linked_monitors = 0; + if ( p_linked_monitors ) + { + int n_link_ids = 0; + unsigned int link_ids[256]; - char link_id_str[8]; - char *dest_ptr = link_id_str; - const char *src_ptr = p_linked_monitors; - while( 1 ) - { - dest_ptr = link_id_str; - while( *src_ptr >= '0' && *src_ptr <= '9' ) - { - if ( (dest_ptr-link_id_str) < (unsigned int)(sizeof(link_id_str)-1) ) - { - *dest_ptr++ = *src_ptr++; - } - else - { - break; - } - } - // Add the link monitor - if ( dest_ptr != link_id_str ) - { - *dest_ptr = '\0'; - unsigned int link_id = atoi(link_id_str); - if ( link_id > 0 && link_id != id) - { - Debug( 3, "Found linked monitor id %d", link_id ); - int j; - for ( j = 0; j < n_link_ids; j++ ) - { - if ( link_ids[j] == link_id ) - break; - } - if ( j == n_link_ids ) // Not already found - { - link_ids[n_link_ids++] = link_id; - } - } - } - if ( !*src_ptr ) - break; - while( *src_ptr && (*src_ptr < '0' || *src_ptr > '9') ) - src_ptr++; - if ( !*src_ptr ) - break; - } - if ( n_link_ids > 0 ) - { - Debug( 1, "Linking to %d monitors", n_link_ids ); - linked_monitors = new MonitorLink *[n_link_ids]; - int count = 0; - for ( int i = 0; i < n_link_ids; i++ ) - { - Debug( 1, "Checking linked monitor %d", link_ids[i] ); + char link_id_str[8]; + char *dest_ptr = link_id_str; + const char *src_ptr = p_linked_monitors; + while( 1 ) + { + dest_ptr = link_id_str; + while( *src_ptr >= '0' && *src_ptr <= '9' ) + { + if ( (dest_ptr-link_id_str) < (unsigned int)(sizeof(link_id_str)-1) ) + { + *dest_ptr++ = *src_ptr++; + } + else + { + break; + } + } + // Add the link monitor + if ( dest_ptr != link_id_str ) + { + *dest_ptr = '\0'; + unsigned int link_id = atoi(link_id_str); + if ( link_id > 0 && link_id != id) + { + Debug( 3, "Found linked monitor id %d", link_id ); + int j; + for ( j = 0; j < n_link_ids; j++ ) + { + if ( link_ids[j] == link_id ) + break; + } + if ( j == n_link_ids ) // Not already found + { + link_ids[n_link_ids++] = link_id; + } + } + } + if ( !*src_ptr ) + break; + while( *src_ptr && (*src_ptr < '0' || *src_ptr > '9') ) + src_ptr++; + if ( !*src_ptr ) + break; + } + if ( n_link_ids > 0 ) + { + Debug( 1, "Linking to %d monitors", n_link_ids ); + linked_monitors = new MonitorLink *[n_link_ids]; + int count = 0; + for ( int i = 0; i < n_link_ids; i++ ) + { + Debug( 1, "Checking linked monitor %d", link_ids[i] ); - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id, Name from Monitors where Id = %d and Function != 'None' and Function != 'Monitor' and Enabled = 1", link_ids[i] ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "select Id, Name from Monitors where Id = %d and Function != 'None' and Function != 'Monitor' and Enabled = 1", link_ids[i] ); + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) - { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - int n_monitors = mysql_num_rows( result ); - if ( n_monitors == 1 ) - { - MYSQL_ROW dbrow = mysql_fetch_row( result ); - Debug( 1, "Linking to monitor %d", link_ids[i] ); - linked_monitors[count++] = new MonitorLink( link_ids[i], dbrow[1] ); - } - else - { - Warning( "Can't link to monitor %d, invalid id, function or not enabled", link_ids[i] ); - } - mysql_free_result( result ); - } - n_linked_monitors = count; - } - } + MYSQL_RES *result = mysql_store_result( &dbconn ); + if ( !result ) + { + Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + int n_monitors = mysql_num_rows( result ); + if ( n_monitors == 1 ) + { + MYSQL_ROW dbrow = mysql_fetch_row( result ); + Debug( 1, "Linking to monitor %d", link_ids[i] ); + linked_monitors[count++] = new MonitorLink( link_ids[i], dbrow[1] ); + } + else + { + Warning( "Can't link to monitor %d, invalid id, function or not enabled", link_ids[i] ); + } + mysql_free_result( result ); + } + n_linked_monitors = count; + } + } } #if ZM_HAS_V4L int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'"; - if ( device[0] ) { - sql += " AND Device='"; - sql += device; - sql += "'"; - } - if ( staticConfig.SERVER_ID ) { - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); - } + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'"; + if ( device[0] ) { + sql += " AND Device='"; + sql += device; + sql += "'"; + } + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); + } Debug( 1, "Loading Local Monitors with %s", sql.c_str() ); - MYSQL_RES *result = zmDbFetch( sql.c_str() ); - if ( !result ) { - Error( "Can't load local monitors: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) - { - int col = 0; + MYSQL_RES *result = zmDbFetch( sql.c_str() ); + if ( !result ) { + Error( "Can't load local monitors: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + int n_monitors = mysql_num_rows( result ); + Debug( 1, "Got %d monitors", n_monitors ); + delete[] monitors; + monitors = new Monitor *[n_monitors]; + for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) + { + int col = 0; - int id = atoi(dbrow[col]); col++; - const char *name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col]; col++; + int id = atoi(dbrow[col]); col++; + const char *name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + int function = atoi(dbrow[col]); col++; + int enabled = atoi(dbrow[col]); col++; + const char *linked_monitors = dbrow[col]; col++; - const char *device = dbrow[col]; col++; - int channel = atoi(dbrow[col]); col++; - int format = atoi(dbrow[col]); col++; + const char *device = dbrow[col]; col++; + int channel = atoi(dbrow[col]); col++; + int format = atoi(dbrow[col]); col++; bool v4l_multi_buffer = config.v4l_multi_buffer; if ( dbrow[col] ) { if (*dbrow[col] == '0' ) { @@ -2136,947 +2101,943 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose } Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); col++; - const char *method = dbrow[col]; col++; + const char *method = dbrow[col]; col++; - int width = atoi(dbrow[col]); col++; - int height = atoi(dbrow[col]); col++; - int colours = atoi(dbrow[col]); col++; - int palette = atoi(dbrow[col]); col++; - Orientation orientation = (Orientation)atoi(dbrow[col]); col++; - unsigned int deinterlacing = atoi(dbrow[col]); col++; + int width = atoi(dbrow[col]); col++; + int height = atoi(dbrow[col]); col++; + int colours = atoi(dbrow[col]); col++; + int palette = atoi(dbrow[col]); col++; + Orientation orientation = (Orientation)atoi(dbrow[col]); col++; + unsigned int deinterlacing = atoi(dbrow[col]); col++; - int savejpegs = atoi(dbrow[col]); col++; - int videowriter = atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col]; col++; + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + bool record_audio = (*dbrow[col] != '0'); col++; - int brightness = atoi(dbrow[col]); col++; - int contrast = atoi(dbrow[col]); col++; - int hue = atoi(dbrow[col]); col++; - int colour = atoi(dbrow[col]); col++; + int brightness = atoi(dbrow[col]); col++; + int contrast = atoi(dbrow[col]); col++; + int hue = atoi(dbrow[col]); col++; + int colour = atoi(dbrow[col]); col++; - const char *event_prefix = dbrow[col]; col++; - const char *label_format = dbrow[col]; col++; + const char *event_prefix = dbrow[col]; col++; + const char *label_format = dbrow[col]; col++; - int label_x = atoi(dbrow[col]); col++; - int label_y = atoi(dbrow[col]); col++; - int label_size = atoi(dbrow[col]); col++; + int label_x = atoi(dbrow[col]); col++; + int label_y = atoi(dbrow[col]); col++; + int label_size = atoi(dbrow[col]); col++; - int image_buffer_count = atoi(dbrow[col]); col++; - int warmup_count = atoi(dbrow[col]); col++; - int pre_event_count = atoi(dbrow[col]); col++; - int post_event_count = atoi(dbrow[col]); col++; - int stream_replay_buffer = atoi(dbrow[col]); col++; - int alarm_frame_count = atoi(dbrow[col]); col++; - int section_length = atoi(dbrow[col]); col++; - int frame_skip = atoi(dbrow[col]); col++; - int motion_frame_skip = atoi(dbrow[col]); col++; - double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; - unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); - int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int fps_report_interval = atoi(dbrow[col]); col++; - int ref_blend_perc = atoi(dbrow[col]); col++; - int alarm_ref_blend_perc = atoi(dbrow[col]); col++; - int track_motion = atoi(dbrow[col]); col++; + int image_buffer_count = atoi(dbrow[col]); col++; + int warmup_count = atoi(dbrow[col]); col++; + int pre_event_count = atoi(dbrow[col]); col++; + int post_event_count = atoi(dbrow[col]); col++; + int stream_replay_buffer = atoi(dbrow[col]); col++; + int alarm_frame_count = atoi(dbrow[col]); col++; + int section_length = atoi(dbrow[col]); col++; + int frame_skip = atoi(dbrow[col]); col++; + int motion_frame_skip = atoi(dbrow[col]); col++; + double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; + unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); + int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int fps_report_interval = atoi(dbrow[col]); col++; + int ref_blend_perc = atoi(dbrow[col]); col++; + int alarm_ref_blend_perc = atoi(dbrow[col]); col++; + int track_motion = atoi(dbrow[col]); col++; - int signal_check_colour; - if ( dbrow[col][0] == '#' ) - signal_check_colour = strtol(dbrow[col]+1,0,16); - else - signal_check_colour = strtol(dbrow[col],0,16); - col++; - bool embed_exif = (*dbrow[col] != '0'); col++; + int signal_check_colour; + if ( dbrow[col][0] == '#' ) + signal_check_colour = strtol(dbrow[col]+1,0,16); + else + signal_check_colour = strtol(dbrow[col],0,16); + col++; + bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); + int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); + int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - int extras = (deinterlacing>>24)&0xff; + int extras = (deinterlacing>>24)&0xff; - Camera *camera = new LocalCamera( - id, - device, - channel, - format, + Camera *camera = new LocalCamera( + id, + device, + channel, + format, v4l_multi_buffer, v4l_captures_per_frame, - method, - cam_width, - cam_height, - colours, - palette, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - extras - ); + method, + cam_width, + cam_height, + colours, + palette, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio, + extras + ); - monitors[i] = new Monitor( - id, - name, - server_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - videowriter, - encoderparams, - event_prefix, - label_format, - Coord( label_x, label_y ), - label_size, - image_buffer_count, - warmup_count, - pre_event_count, - post_event_count, - stream_replay_buffer, - alarm_frame_count, - section_length, - frame_skip, - motion_frame_skip, - analysis_fps, - analysis_update_delay, - capture_delay, - alarm_capture_delay, - fps_report_interval, - ref_blend_perc, - alarm_ref_blend_perc, - track_motion, - signal_check_colour, - embed_exif, - purpose, - 0, - 0 - ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); - } - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); + monitors[i] = new Monitor( + id, + name, + server_id, + function, + enabled, + linked_monitors, + camera, + orientation, + deinterlacing, + savejpegs, + videowriter, + encoderparams, + record_audio, + event_prefix, + label_format, + Coord( label_x, label_y ), + label_size, + image_buffer_count, + warmup_count, + pre_event_count, + post_event_count, + stream_replay_buffer, + alarm_frame_count, + section_length, + frame_skip, + motion_frame_skip, + analysis_fps, + analysis_update_delay, + capture_delay, + alarm_capture_delay, + fps_report_interval, + ref_blend_perc, + alarm_ref_blend_perc, + track_motion, + signal_check_colour, + embed_exif, + purpose, + 0, + 0 + ); + Zone **zones = 0; + int n_zones = Zone::Load( monitors[i], zones ); + monitors[i]->AddZones( n_zones, zones ); + monitors[i]->AddPrivacyBitmask( zones ); + Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); + } + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + // Yadda yadda + mysql_free_result( result ); - return( n_monitors ); + return( n_monitors ); } #endif // ZM_HAS_V4L int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'"; - if ( staticConfig.SERVER_ID ) { - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); - } + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'"; + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); + } - if ( protocol ) { - sql += stringtf(" AND Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path ); - } + if ( protocol ) { + sql += stringtf(" AND Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path ); + } Debug( 1, "Loading Remote Monitors with %s", sql.c_str() ); - MYSQL_RES *result = zmDbFetch( sql.c_str() ); - if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) - { - int col = 0; + MYSQL_RES *result = zmDbFetch( sql.c_str() ); + if ( !result ) { + Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + int n_monitors = mysql_num_rows( result ); + Debug( 1, "Got %d monitors", n_monitors ); + delete[] monitors; + monitors = new Monitor *[n_monitors]; + for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) + { + int col = 0; - int id = atoi(dbrow[col]); col++; - std::string name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col]; col++; + int id = atoi(dbrow[col]); col++; + std::string name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + int function = atoi(dbrow[col]); col++; + int enabled = atoi(dbrow[col]); col++; + const char *linked_monitors = dbrow[col]; col++; - std::string protocol = dbrow[col]; col++; - std::string method = dbrow[col]; col++; - std::string host = dbrow[col]; col++; - std::string port = dbrow[col]; col++; - std::string path = dbrow[col]; col++; + std::string protocol = dbrow[col]; col++; + std::string method = dbrow[col]; col++; + std::string host = dbrow[col]; col++; + std::string port = dbrow[col]; col++; + std::string path = dbrow[col]; col++; - int width = atoi(dbrow[col]); col++; - int height = atoi(dbrow[col]); col++; - int colours = atoi(dbrow[col]); col++; - /* int palette = atoi(dbrow[col]); */ col++; - Orientation orientation = (Orientation)atoi(dbrow[col]); col++; - unsigned int deinterlacing = atoi(dbrow[col]); col++; - bool rtsp_describe = (*dbrow[col] != '0'); col++; - int savejpegs = atoi(dbrow[col]); col++; - int videowriter = atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col]; col++; - - int brightness = atoi(dbrow[col]); col++; - int contrast = atoi(dbrow[col]); col++; - int hue = atoi(dbrow[col]); col++; - int colour = atoi(dbrow[col]); col++; + int width = atoi(dbrow[col]); col++; + int height = atoi(dbrow[col]); col++; + int colours = atoi(dbrow[col]); col++; + /* int palette = atoi(dbrow[col]); */ col++; + Orientation orientation = (Orientation)atoi(dbrow[col]); col++; + unsigned int deinterlacing = atoi(dbrow[col]); col++; + bool rtsp_describe = (*dbrow[col] != '0'); col++; + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + bool record_audio = (*dbrow[col] != '0'); col++; + + int brightness = atoi(dbrow[col]); col++; + int contrast = atoi(dbrow[col]); col++; + int hue = atoi(dbrow[col]); col++; + int colour = atoi(dbrow[col]); col++; - std::string event_prefix = dbrow[col]; col++; - std::string label_format = dbrow[col]; col++; + std::string event_prefix = dbrow[col]; col++; + std::string label_format = dbrow[col]; col++; - int label_x = atoi(dbrow[col]); col++; - int label_y = atoi(dbrow[col]); col++; - int label_size = atoi(dbrow[col]); col++; + int label_x = atoi(dbrow[col]); col++; + int label_y = atoi(dbrow[col]); col++; + int label_size = atoi(dbrow[col]); col++; - int image_buffer_count = atoi(dbrow[col]); col++; - int warmup_count = atoi(dbrow[col]); col++; - int pre_event_count = atoi(dbrow[col]); col++; - int post_event_count = atoi(dbrow[col]); col++; - int stream_replay_buffer = atoi(dbrow[col]); col++; - int alarm_frame_count = atoi(dbrow[col]); col++; - int section_length = atoi(dbrow[col]); col++; - int frame_skip = atoi(dbrow[col]); col++; - int motion_frame_skip = atoi(dbrow[col]); col++; - double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; - unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); - int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int fps_report_interval = atoi(dbrow[col]); col++; - int ref_blend_perc = atoi(dbrow[col]); col++; - int alarm_ref_blend_perc = atoi(dbrow[col]); col++; - int track_motion = atoi(dbrow[col]); col++; - bool embed_exif = (*dbrow[col] != '0'); col++; + int image_buffer_count = atoi(dbrow[col]); col++; + int warmup_count = atoi(dbrow[col]); col++; + int pre_event_count = atoi(dbrow[col]); col++; + int post_event_count = atoi(dbrow[col]); col++; + int stream_replay_buffer = atoi(dbrow[col]); col++; + int alarm_frame_count = atoi(dbrow[col]); col++; + int section_length = atoi(dbrow[col]); col++; + int frame_skip = atoi(dbrow[col]); col++; + int motion_frame_skip = atoi(dbrow[col]); col++; + double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; + unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); + int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int fps_report_interval = atoi(dbrow[col]); col++; + int ref_blend_perc = atoi(dbrow[col]); col++; + int alarm_ref_blend_perc = atoi(dbrow[col]); col++; + int track_motion = atoi(dbrow[col]); col++; + bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); + int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); + int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - Camera *camera = 0; - if ( protocol == "http" ) - { - camera = new RemoteCameraHttp( - id, - method, - host, // Host - port, // Port - path, // Path - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); - } + Camera *camera = 0; + if ( protocol == "http" ) { + camera = new RemoteCameraHttp( + id, + method, + host, // Host + port, // Port + path, // Path + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); + } #if HAVE_LIBAVFORMAT - else if ( protocol == "rtsp" ) - { - camera = new RemoteCameraRtsp( - id, - method, - host, // Host - port, // Port - path, // Path - cam_width, - cam_height, - rtsp_describe, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); - } + else if ( protocol == "rtsp" ) { + camera = new RemoteCameraRtsp( + id, + method, + host, // Host + port, // Port + path, // Path + cam_width, + cam_height, + rtsp_describe, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); + } #endif // HAVE_LIBAVFORMAT - else - { - Fatal( "Unexpected remote camera protocol '%s'", protocol.c_str() ); - } + else { + Fatal( "Unexpected remote camera protocol '%s'", protocol.c_str() ); + } - monitors[i] = new Monitor( - id, - name.c_str(), - server_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - videowriter, - encoderparams, - event_prefix.c_str(), - label_format.c_str(), - Coord( label_x, label_y ), - label_size, - image_buffer_count, - warmup_count, - pre_event_count, - post_event_count, - stream_replay_buffer, - alarm_frame_count, - section_length, - frame_skip, - motion_frame_skip, - analysis_fps, - analysis_update_delay, - capture_delay, - alarm_capture_delay, - fps_report_interval, - ref_blend_perc, - alarm_ref_blend_perc, - track_motion, - RGB_WHITE, - embed_exif, - purpose, - 0, - 0 + monitors[i] = new Monitor( + id, + name.c_str(), + server_id, + function, + enabled, + linked_monitors, + camera, + orientation, + deinterlacing, + savejpegs, + videowriter, + encoderparams, + record_audio, + event_prefix.c_str(), + label_format.c_str(), + Coord( label_x, label_y ), + label_size, + image_buffer_count, + warmup_count, + pre_event_count, + post_event_count, + stream_replay_buffer, + alarm_frame_count, + section_length, + frame_skip, + motion_frame_skip, + analysis_fps, + analysis_update_delay, + capture_delay, + alarm_capture_delay, + fps_report_interval, + ref_blend_perc, + alarm_ref_blend_perc, + track_motion, + RGB_WHITE, + embed_exif, + purpose, + 0, + 0 + ); + Zone **zones = 0; + int n_zones = Zone::Load( monitors[i], zones ); + monitors[i]->AddZones( n_zones, zones ); + monitors[i]->AddPrivacyBitmask( zones ); + Debug( 1, "Loaded monitor %d(%s), %d zones", id, name.c_str(), n_zones ); + } + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + // Yadda yadda + mysql_free_result( result ); - ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name.c_str(), n_zones ); - } - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); - - return( n_monitors ); + return( n_monitors ); } -int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) -{ - std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'"; - if ( file[0] ) { - sql += " AND Path='"; - sql += file; - sql += "'"; - } - if ( staticConfig.SERVER_ID ) { - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); - } +int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'"; + if ( file[0] ) { + sql += " AND Path='"; + sql += file; + sql += "'"; + } + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); + } Debug( 1, "Loading File Monitors with %s", sql.c_str() ); - MYSQL_RES *result = zmDbFetch( sql.c_str() ); - if ( !result ) - { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) - { - int col = 0; + MYSQL_RES *result = zmDbFetch( sql.c_str() ); + if ( !result ) + { + Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + int n_monitors = mysql_num_rows( result ); + Debug( 1, "Got %d monitors", n_monitors ); + delete[] monitors; + monitors = new Monitor *[n_monitors]; + for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) + { + int col = 0; - int id = atoi(dbrow[col]); col++; - const char *name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col]; col++; + int id = atoi(dbrow[col]); col++; + const char *name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + int function = atoi(dbrow[col]); col++; + int enabled = atoi(dbrow[col]); col++; + const char *linked_monitors = dbrow[col]; col++; - const char *path = dbrow[col]; col++; + const char *path = dbrow[col]; col++; - int width = atoi(dbrow[col]); col++; - int height = atoi(dbrow[col]); col++; - int colours = atoi(dbrow[col]); col++; - /* int palette = atoi(dbrow[col]); */ col++; - Orientation orientation = (Orientation)atoi(dbrow[col]); col++; - unsigned int deinterlacing = atoi(dbrow[col]); col++; + int width = atoi(dbrow[col]); col++; + int height = atoi(dbrow[col]); col++; + int colours = atoi(dbrow[col]); col++; + /* int palette = atoi(dbrow[col]); */ col++; + Orientation orientation = (Orientation)atoi(dbrow[col]); col++; + unsigned int deinterlacing = atoi(dbrow[col]); col++; - int savejpegs = atoi(dbrow[col]); col++; - int videowriter = atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col]; col++; + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + bool record_audio = (*dbrow[col] != '0'); col++; - int brightness = atoi(dbrow[col]); col++; - int contrast = atoi(dbrow[col]); col++; - int hue = atoi(dbrow[col]); col++; - int colour = atoi(dbrow[col]); col++; + int brightness = atoi(dbrow[col]); col++; + int contrast = atoi(dbrow[col]); col++; + int hue = atoi(dbrow[col]); col++; + int colour = atoi(dbrow[col]); col++; - const char *event_prefix = dbrow[col]; col++; - const char *label_format = dbrow[col]; col++; + const char *event_prefix = dbrow[col]; col++; + const char *label_format = dbrow[col]; col++; - int label_x = atoi(dbrow[col]); col++; - int label_y = atoi(dbrow[col]); col++; - int label_size = atoi(dbrow[col]); col++; + int label_x = atoi(dbrow[col]); col++; + int label_y = atoi(dbrow[col]); col++; + int label_size = atoi(dbrow[col]); col++; - int image_buffer_count = atoi(dbrow[col]); col++; - int warmup_count = atoi(dbrow[col]); col++; - int pre_event_count = atoi(dbrow[col]); col++; - int post_event_count = atoi(dbrow[col]); col++; - int stream_replay_buffer = atoi(dbrow[col]); col++; - int alarm_frame_count = atoi(dbrow[col]); col++; - int section_length = atoi(dbrow[col]); col++; - int frame_skip = atoi(dbrow[col]); col++; - int motion_frame_skip = atoi(dbrow[col]); col++; - double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; - unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); - int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int fps_report_interval = atoi(dbrow[col]); col++; - int ref_blend_perc = atoi(dbrow[col]); col++; - int alarm_ref_blend_perc = atoi(dbrow[col]); col++; - int track_motion = atoi(dbrow[col]); col++; - bool embed_exif = (*dbrow[col] != '0'); col++; + int image_buffer_count = atoi(dbrow[col]); col++; + int warmup_count = atoi(dbrow[col]); col++; + int pre_event_count = atoi(dbrow[col]); col++; + int post_event_count = atoi(dbrow[col]); col++; + int stream_replay_buffer = atoi(dbrow[col]); col++; + int alarm_frame_count = atoi(dbrow[col]); col++; + int section_length = atoi(dbrow[col]); col++; + int frame_skip = atoi(dbrow[col]); col++; + int motion_frame_skip = atoi(dbrow[col]); col++; + double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; + unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); + int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int fps_report_interval = atoi(dbrow[col]); col++; + int ref_blend_perc = atoi(dbrow[col]); col++; + int alarm_ref_blend_perc = atoi(dbrow[col]); col++; + int track_motion = atoi(dbrow[col]); col++; + bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); + int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); + int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - Camera *camera = new FileCamera( - id, - path, // File - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); + Camera *camera = new FileCamera( + id, + path, // File + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); - monitors[i] = new Monitor( - id, - name, - server_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - videowriter, - encoderparams, - event_prefix, - label_format, - Coord( label_x, label_y ), - label_size, - image_buffer_count, - warmup_count, - pre_event_count, - post_event_count, - stream_replay_buffer, - alarm_frame_count, - section_length, - frame_skip, - motion_frame_skip, - analysis_fps, - analysis_update_delay, - capture_delay, - alarm_capture_delay, - fps_report_interval, - ref_blend_perc, - alarm_ref_blend_perc, - track_motion, - embed_exif, - RGB_WHITE, - purpose, - 0, - 0 - ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); - } - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); + monitors[i] = new Monitor( + id, + name, + server_id, + function, + enabled, + linked_monitors, + camera, + orientation, + deinterlacing, + savejpegs, + videowriter, + encoderparams, + record_audio, + event_prefix, + label_format, + Coord( label_x, label_y ), + label_size, + image_buffer_count, + warmup_count, + pre_event_count, + post_event_count, + stream_replay_buffer, + alarm_frame_count, + section_length, + frame_skip, + motion_frame_skip, + analysis_fps, + analysis_update_delay, + capture_delay, + alarm_capture_delay, + fps_report_interval, + ref_blend_perc, + alarm_ref_blend_perc, + track_motion, + embed_exif, + RGB_WHITE, + purpose, + 0, + 0 + ); + Zone **zones = 0; + int n_zones = Zone::Load( monitors[i], zones ); + monitors[i]->AddZones( n_zones, zones ); + monitors[i]->AddPrivacyBitmask( zones ); + Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); + } + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + // Yadda yadda + mysql_free_result( result ); - return( n_monitors ); + return( n_monitors ); } #if HAVE_LIBAVFORMAT int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'"; - if ( file[0] ) { - sql += " AND Path = '"; - sql += file; - sql += "'"; - } - if ( staticConfig.SERVER_ID ) { - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); - } + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'"; + if ( file[0] ) { + sql += " AND Path = '"; + sql += file; + sql += "'"; + } + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); + } Debug( 1, "Loading FFMPEG Monitors with %s", sql.c_str() ); - MYSQL_RES *result = zmDbFetch( sql.c_str() ); - if ( ! result ) { - Error( "Cannot load FfmpegMonitors" ); - exit( mysql_errno( &dbconn ) ); - } + MYSQL_RES *result = zmDbFetch( sql.c_str() ); + if ( ! result ) { + Error( "Cannot load FfmpegMonitors" ); + exit( mysql_errno( &dbconn ) ); + } - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) - { - int col = 0; + int n_monitors = mysql_num_rows( result ); + Debug( 1, "Got %d monitors", n_monitors ); + delete[] monitors; + monitors = new Monitor *[n_monitors]; + for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { + int col = 0; - int id = atoi(dbrow[col]); col++; - const char *name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col]; col++; + int id = atoi(dbrow[col]); col++; + const char *name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + int function = atoi(dbrow[col]); col++; + int enabled = atoi(dbrow[col]); col++; + const char *linked_monitors = dbrow[col]; col++; - const char *path = dbrow[col]; col++; - const char *method = dbrow[col]; col++; - const char *options = dbrow[col]; col++; + const char *path = dbrow[col]; col++; + const char *method = dbrow[col]; col++; + const char *options = dbrow[col]; col++; - int width = atoi(dbrow[col]); col++; - int height = atoi(dbrow[col]); col++; - int colours = atoi(dbrow[col]); col++; - /* int palette = atoi(dbrow[col]); */ col++; - Orientation orientation = (Orientation)atoi(dbrow[col]); col++; - unsigned int deinterlacing = atoi(dbrow[col]); col++; + int width = atoi(dbrow[col]); col++; + int height = atoi(dbrow[col]); col++; + int colours = atoi(dbrow[col]); col++; + /* int palette = atoi(dbrow[col]); */ col++; + Orientation orientation = (Orientation)atoi(dbrow[col]); col++; + unsigned int deinterlacing = atoi(dbrow[col]); col++; - int savejpegs = atoi(dbrow[col]); col++; - int videowriter = atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col]; col++; + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + bool record_audio = (*dbrow[col] != '0'); col++; - int brightness = atoi(dbrow[col]); col++; - int contrast = atoi(dbrow[col]); col++; - int hue = atoi(dbrow[col]); col++; - int colour = atoi(dbrow[col]); col++; + int brightness = atoi(dbrow[col]); col++; + int contrast = atoi(dbrow[col]); col++; + int hue = atoi(dbrow[col]); col++; + int colour = atoi(dbrow[col]); col++; - const char *event_prefix = dbrow[col]; col++; - const char *label_format = dbrow[col]; col++; + const char *event_prefix = dbrow[col]; col++; + const char *label_format = dbrow[col]; col++; - int label_x = atoi(dbrow[col]); col++; - int label_y = atoi(dbrow[col]); col++; - int label_size = atoi(dbrow[col]); col++; + int label_x = atoi(dbrow[col]); col++; + int label_y = atoi(dbrow[col]); col++; + int label_size = atoi(dbrow[col]); col++; - int image_buffer_count = atoi(dbrow[col]); col++; - int warmup_count = atoi(dbrow[col]); col++; - int pre_event_count = atoi(dbrow[col]); col++; - int post_event_count = atoi(dbrow[col]); col++; - int stream_replay_buffer = atoi(dbrow[col]); col++; - int alarm_frame_count = atoi(dbrow[col]); col++; - int section_length = atoi(dbrow[col]); col++; - int frame_skip = atoi(dbrow[col]); col++; - int motion_frame_skip = atoi(dbrow[col]); col++; - double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; - unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); - int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int fps_report_interval = atoi(dbrow[col]); col++; - int ref_blend_perc = atoi(dbrow[col]); col++; - int alarm_ref_blend_perc = atoi(dbrow[col]); col++; - int track_motion = atoi(dbrow[col]); col++; - bool embed_exif = (*dbrow[col] != '0'); col++; + int image_buffer_count = atoi(dbrow[col]); col++; + int warmup_count = atoi(dbrow[col]); col++; + int pre_event_count = atoi(dbrow[col]); col++; + int post_event_count = atoi(dbrow[col]); col++; + int stream_replay_buffer = atoi(dbrow[col]); col++; + int alarm_frame_count = atoi(dbrow[col]); col++; + int section_length = atoi(dbrow[col]); col++; + int frame_skip = atoi(dbrow[col]); col++; + int motion_frame_skip = atoi(dbrow[col]); col++; + double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; + unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); + int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int fps_report_interval = atoi(dbrow[col]); col++; + int ref_blend_perc = atoi(dbrow[col]); col++; + int alarm_ref_blend_perc = atoi(dbrow[col]); col++; + int track_motion = atoi(dbrow[col]); col++; + bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); + int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); + int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - Camera *camera = new FfmpegCamera( - id, - path, // File - method, - options, - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); + Camera *camera = new FfmpegCamera( + id, + path, // File + method, + options, + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); - monitors[i] = new Monitor( - id, - name, - server_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - videowriter, - encoderparams, - event_prefix, - label_format, - Coord( label_x, label_y ), - label_size, - image_buffer_count, - warmup_count, - pre_event_count, - post_event_count, - stream_replay_buffer, - alarm_frame_count, - section_length, - frame_skip, - motion_frame_skip, - analysis_fps, - analysis_update_delay, - capture_delay, - alarm_capture_delay, - fps_report_interval, - ref_blend_perc, - alarm_ref_blend_perc, - track_motion, - embed_exif, - RGB_WHITE, - purpose, - 0, - 0 - ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); - } - if ( mysql_errno( &dbconn ) ) - { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); + monitors[i] = new Monitor( + id, + name, + server_id, + function, + enabled, + linked_monitors, + camera, + orientation, + deinterlacing, + savejpegs, + videowriter, + encoderparams, + record_audio, + event_prefix, + label_format, + Coord( label_x, label_y ), + label_size, + image_buffer_count, + warmup_count, + pre_event_count, + post_event_count, + stream_replay_buffer, + alarm_frame_count, + section_length, + frame_skip, + motion_frame_skip, + analysis_fps, + analysis_update_delay, + capture_delay, + alarm_capture_delay, + fps_report_interval, + ref_blend_perc, + alarm_ref_blend_perc, + track_motion, + embed_exif, + RGB_WHITE, + purpose, + 0, + 0 + ); + Zone **zones = 0; + int n_zones = Zone::Load( monitors[i], zones ); + monitors[i]->AddZones( n_zones, zones ); + monitors[i]->AddPrivacyBitmask( zones ); + Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); + } + if ( mysql_errno( &dbconn ) ) + { + Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + // Yadda yadda + mysql_free_result( result ); - return( n_monitors ); + return( n_monitors ); } #endif // HAVE_LIBAVFORMAT -Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) -{ - std::string sql = stringtf( "select Id, Name, ServerId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id ); +Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { + std::string sql = stringtf( "select Id, Name, ServerId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id ); - MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ); - if ( ! dbrow ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - Monitor *monitor = 0; - unsigned int col = 0; + MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ); + if ( ! dbrow ) { + Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + Monitor *monitor = 0; + unsigned int col = 0; - unsigned int id = atoi(dbrow[col]); col++; - std::string name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - std::string type = dbrow[col]; col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - std::string linked_monitors = dbrow[col]; col++; + unsigned int id = atoi(dbrow[col]); col++; + std::string name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + std::string type = dbrow[col]; col++; + int function = atoi(dbrow[col]); col++; + int enabled = atoi(dbrow[col]); col++; + std::string linked_monitors = dbrow[col]; col++; - std::string device = dbrow[col]; col++; - int channel = atoi(dbrow[col]); col++; - int format = atoi(dbrow[col]); col++; + std::string device = dbrow[col]; col++; + int channel = atoi(dbrow[col]); col++; + int format = atoi(dbrow[col]); col++; - bool v4l_multi_buffer = config.v4l_multi_buffer; - if ( dbrow[col] ) { - if (*dbrow[col] == '0' ) { - v4l_multi_buffer = false; - } else if ( *dbrow[col] == '1' ) { - v4l_multi_buffer = true; - } - } - col++; - - int v4l_captures_per_frame = 0; - if ( dbrow[col] ) { - v4l_captures_per_frame = atoi(dbrow[col]); - } else { - v4l_captures_per_frame = config.captures_per_frame; - } -Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); - col++; - - std::string protocol = dbrow[col]; col++; - std::string method = dbrow[col]; col++; - std::string host = dbrow[col]; col++; - std::string port = dbrow[col]; col++; - std::string path = dbrow[col]; col++; - std::string options = dbrow[col]; col++; - std::string user = dbrow[col]; col++; - std::string pass = dbrow[col]; col++; - - int width = atoi(dbrow[col]); col++; - int height = atoi(dbrow[col]); col++; - int colours = atoi(dbrow[col]); col++; - int palette = atoi(dbrow[col]); col++; - Orientation orientation = (Orientation)atoi(dbrow[col]); col++; - unsigned int deinterlacing = atoi(dbrow[col]); col++; - bool rtsp_describe = (*dbrow[col] != '0'); col++; - int savejpegs = atoi(dbrow[col]); col++; - int videowriter = atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col]; col++; - - int brightness = atoi(dbrow[col]); col++; - int contrast = atoi(dbrow[col]); col++; - int hue = atoi(dbrow[col]); col++; - int colour = atoi(dbrow[col]); col++; - - std::string event_prefix = dbrow[col]; col++; - std::string label_format = dbrow[col]; col++; - - int label_x = atoi(dbrow[col]); col++; - int label_y = atoi(dbrow[col]); col++; - int label_size = atoi(dbrow[col]); col++; - - int image_buffer_count = atoi(dbrow[col]); col++; - int warmup_count = atoi(dbrow[col]); col++; - int pre_event_count = atoi(dbrow[col]); col++; - int post_event_count = atoi(dbrow[col]); col++; - int stream_replay_buffer = atoi(dbrow[col]); col++; - int alarm_frame_count = atoi(dbrow[col]); col++; - int section_length = atoi(dbrow[col]); col++; - int frame_skip = atoi(dbrow[col]); col++; - int motion_frame_skip = atoi(dbrow[col]); col++; - double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; - unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); - int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int fps_report_interval = atoi(dbrow[col]); col++; - int ref_blend_perc = atoi(dbrow[col]); col++; - int alarm_ref_blend_perc = atoi(dbrow[col]); col++; - int track_motion = atoi(dbrow[col]); col++; - - int signal_check_colour; - if ( dbrow[col][0] == '#' ) - signal_check_colour = strtol(dbrow[col]+1,0,16); - else - signal_check_colour = strtol(dbrow[col],0,16); + bool v4l_multi_buffer = config.v4l_multi_buffer; + if ( dbrow[col] ) { + if (*dbrow[col] == '0' ) { + v4l_multi_buffer = false; + } else if ( *dbrow[col] == '1' ) { + v4l_multi_buffer = true; + } + } col++; - bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); + int v4l_captures_per_frame = 0; + if ( dbrow[col] ) { + v4l_captures_per_frame = atoi(dbrow[col]); + } else { + v4l_captures_per_frame = config.captures_per_frame; + } + Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); + col++; - int extras = (deinterlacing>>24)&0xff; + std::string protocol = dbrow[col]; col++; + std::string method = dbrow[col]; col++; + std::string host = dbrow[col]; col++; + std::string port = dbrow[col]; col++; + std::string path = dbrow[col]; col++; + std::string options = dbrow[col]; col++; + std::string user = dbrow[col]; col++; + std::string pass = dbrow[col]; col++; - Camera *camera = 0; - if ( type == "Local" ) - { + int width = atoi(dbrow[col]); col++; + int height = atoi(dbrow[col]); col++; + int colours = atoi(dbrow[col]); col++; + int palette = atoi(dbrow[col]); col++; + Orientation orientation = (Orientation)atoi(dbrow[col]); col++; + unsigned int deinterlacing = atoi(dbrow[col]); col++; + bool rtsp_describe = (*dbrow[col] != '0'); col++; + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + bool record_audio = (*dbrow[col] != '0'); col++; + + int brightness = atoi(dbrow[col]); col++; + int contrast = atoi(dbrow[col]); col++; + int hue = atoi(dbrow[col]); col++; + int colour = atoi(dbrow[col]); col++; + + std::string event_prefix = dbrow[col]; col++; + std::string label_format = dbrow[col]; col++; + + int label_x = atoi(dbrow[col]); col++; + int label_y = atoi(dbrow[col]); col++; + int label_size = atoi(dbrow[col]); col++; + + int image_buffer_count = atoi(dbrow[col]); col++; + int warmup_count = atoi(dbrow[col]); col++; + int pre_event_count = atoi(dbrow[col]); col++; + int post_event_count = atoi(dbrow[col]); col++; + int stream_replay_buffer = atoi(dbrow[col]); col++; + int alarm_frame_count = atoi(dbrow[col]); col++; + int section_length = atoi(dbrow[col]); col++; + int frame_skip = atoi(dbrow[col]); col++; + int motion_frame_skip = atoi(dbrow[col]); col++; + double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; + unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); + int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int fps_report_interval = atoi(dbrow[col]); col++; + int ref_blend_perc = atoi(dbrow[col]); col++; + int alarm_ref_blend_perc = atoi(dbrow[col]); col++; + int track_motion = atoi(dbrow[col]); col++; + + int signal_check_colour; + if ( dbrow[col][0] == '#' ) + signal_check_colour = strtol(dbrow[col]+1,0,16); + else + signal_check_colour = strtol(dbrow[col],0,16); + col++; + bool embed_exif = (*dbrow[col] != '0'); col++; + + int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); + int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); + + int extras = (deinterlacing>>24)&0xff; + + Camera *camera = 0; + if ( type == "Local" ) { #if ZM_HAS_V4L - camera = new LocalCamera( - id, - device.c_str(), - channel, - format, - v4l_multi_buffer, - v4l_captures_per_frame, - method, - cam_width, - cam_height, - colours, - palette, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - extras - ); + camera = new LocalCamera( + id, + device.c_str(), + channel, + format, + v4l_multi_buffer, + v4l_captures_per_frame, + method, + cam_width, + cam_height, + colours, + palette, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio, + extras + ); #else // ZM_HAS_V4L - Fatal( "You must have video4linux libraries and headers installed to use local analog or USB cameras for monitor %d", id ); + Fatal( "You must have video4linux libraries and headers installed to use local analog or USB cameras for monitor %d", id ); #endif // ZM_HAS_V4L - } - else if ( type == "Remote" ) - { - if ( protocol == "http" ) - { - camera = new RemoteCameraHttp( - id, - method.c_str(), - host.c_str(), - port.c_str(), - path.c_str(), - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); - } - else if ( protocol == "rtsp" ) - { + } else if ( type == "Remote" ) { + if ( protocol == "http" ) { + camera = new RemoteCameraHttp( + id, + method.c_str(), + host.c_str(), + port.c_str(), + path.c_str(), + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); + } else if ( protocol == "rtsp" ) { #if HAVE_LIBAVFORMAT - camera = new RemoteCameraRtsp( - id, - method.c_str(), - host.c_str(), - port.c_str(), - path.c_str(), - cam_width, - cam_height, - rtsp_describe, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); + camera = new RemoteCameraRtsp( + id, + method.c_str(), + host.c_str(), + port.c_str(), + path.c_str(), + cam_width, + cam_height, + rtsp_describe, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); #else // HAVE_LIBAVFORMAT - Fatal( "You must have ffmpeg libraries installed to use remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); + Fatal( "You must have ffmpeg libraries installed to use remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); #endif // HAVE_LIBAVFORMAT - } - else - { - Fatal( "Unexpected remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); - } - } - else if ( type == "File" ) - { - camera = new FileCamera( - id, - path.c_str(), - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); - } - else if ( type == "Ffmpeg" ) - { + } else { + Fatal( "Unexpected remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); + } + } else if ( type == "File" ) { + camera = new FileCamera( + id, + path.c_str(), + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); + } else if ( type == "Ffmpeg" ) { #if HAVE_LIBAVFORMAT - camera = new FfmpegCamera( - id, - path.c_str(), - method, - options, - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); + camera = new FfmpegCamera( + id, + path.c_str(), + method, + options, + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); #else // HAVE_LIBAVFORMAT - Fatal( "You must have ffmpeg libraries installed to use ffmpeg cameras for monitor %d", id ); + Fatal( "You must have ffmpeg libraries installed to use ffmpeg cameras for monitor %d", id ); #endif // HAVE_LIBAVFORMAT - } - else if (type == "Libvlc") - { + } else if (type == "Libvlc") { #if HAVE_LIBVLC - camera = new LibvlcCamera( - id, - path.c_str(), - method, - options, - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); + camera = new LibvlcCamera( + id, + path.c_str(), + method, + options, + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); #else // HAVE_LIBVLC - Fatal( "You must have vlc libraries installed to use vlc cameras for monitor %d", id ); + Fatal( "You must have vlc libraries installed to use vlc cameras for monitor %d", id ); #endif // HAVE_LIBVLC - } - else if ( type == "cURL" ) - { + } else if ( type == "cURL" ) { #if HAVE_LIBCURL - camera = new cURLCamera( - id, - path.c_str(), - user.c_str(), - pass.c_str(), - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); + camera = new cURLCamera( + id, + path.c_str(), + user.c_str(), + pass.c_str(), + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); #else // HAVE_LIBCURL - Fatal( "You must have libcurl installed to use ffmpeg cameras for monitor %d", id ); + Fatal( "You must have libcurl installed to use ffmpeg cameras for monitor %d", id ); #endif // HAVE_LIBCURL - } - else - { - Fatal( "Bogus monitor type '%s' for monitor %d", type.c_str(), id ); - } - monitor = new Monitor( - id, - name.c_str(), - server_id, - function, - enabled, - linked_monitors.c_str(), - camera, - orientation, - deinterlacing, - savejpegs, - videowriter, - encoderparams, - event_prefix.c_str(), - label_format.c_str(), - Coord( label_x, label_y ), - label_size, - image_buffer_count, - warmup_count, - pre_event_count, - post_event_count, - stream_replay_buffer, - alarm_frame_count, - section_length, - frame_skip, - motion_frame_skip, - analysis_fps, - analysis_update_delay, - capture_delay, - alarm_capture_delay, - fps_report_interval, - ref_blend_perc, - alarm_ref_blend_perc, - track_motion, - signal_check_colour, - embed_exif, - purpose, - 0, - 0 + } else { + Fatal( "Bogus monitor type '%s' for monitor %d", type.c_str(), id ); + } + monitor = new Monitor( + id, + name.c_str(), + server_id, + function, + enabled, + linked_monitors.c_str(), + camera, + orientation, + deinterlacing, + savejpegs, + videowriter, + encoderparams, + record_audio, + event_prefix.c_str(), + label_format.c_str(), + Coord( label_x, label_y ), + label_size, + image_buffer_count, + warmup_count, + pre_event_count, + post_event_count, + stream_replay_buffer, + alarm_frame_count, + section_length, + frame_skip, + motion_frame_skip, + analysis_fps, + analysis_update_delay, + capture_delay, + alarm_capture_delay, + fps_report_interval, + ref_blend_perc, + alarm_ref_blend_perc, + track_motion, + signal_check_colour, + embed_exif, + purpose, + 0, + 0 - ); + ); - int n_zones = 0; - if ( load_zones ) - { - Zone **zones = 0; - n_zones = Zone::Load( monitor, zones ); - monitor->AddZones( n_zones, zones ); - monitor->AddPrivacyBitmask( zones ); - } - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name.c_str(), n_zones ); - return( monitor ); + int n_zones = 0; + if ( load_zones ) { + Zone **zones = 0; + n_zones = Zone::Load( monitor, zones ); + monitor->AddZones( n_zones, zones ); + monitor->AddPrivacyBitmask( zones ); + } + Debug( 1, "Loaded monitor %d(%s), %d zones", id, name.c_str(), n_zones ); + return( monitor ); } int Monitor::Capture() @@ -3093,51 +3054,49 @@ int Monitor::Capture() capture_image->CopyBuffer(*(next_buffer.image)); } - /* Capture a new next image */ - - //Check if FFMPEG camera - if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()){ - captureResult = camera->CaptureAndRecord(*(next_buffer.image), video_store_data->recording, video_store_data->event_file); - }else{ - captureResult = camera->Capture(*(next_buffer.image)); - } + /* Capture a new next image */ + + //Check if FFMPEG camera + if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()){ + captureResult = camera->CaptureAndRecord(*(next_buffer.image), video_store_data->recording, video_store_data->event_file); + }else{ + captureResult = camera->Capture(*(next_buffer.image)); + } - if ( FirstCapture ) { - FirstCapture = 0; - return 0; - } + if ( FirstCapture ) { + FirstCapture = 0; + return 0; + } - } else { - //Check if FFMPEG camera - if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()){ - //Warning("ZMC: Recording: %d", video_store_data->recording); - captureResult = camera->CaptureAndRecord(*capture_image, video_store_data->recording, video_store_data->event_file); - }else{ - /* Capture directly into image buffer, avoiding the need to memcpy() */ - captureResult = camera->Capture(*capture_image); - } - } - - if((GetOptVideoWriter() == 2) && captureResult > 0){ - //video_store_data->frameNumber = captureResult; - captureResult = 0; - } - - if ( captureResult != 0 ) - { - // Unable to capture image for temporary reason - // Fake a signal loss image - Rgb signalcolor; - signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */ - capture_image->Fill(signalcolor); - captureResult = 0; - } else { - captureResult = 1; - } - - if ( captureResult == 1 ) - { - + } else { + //Check if FFMPEG camera + if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()){ + //Warning("ZMC: Recording: %d", video_store_data->recording); + captureResult = camera->CaptureAndRecord(*capture_image, video_store_data->recording, video_store_data->event_file); + }else{ + /* Capture directly into image buffer, avoiding the need to memcpy() */ + captureResult = camera->Capture(*capture_image); + } + } + + if((GetOptVideoWriter() == 2) && captureResult > 0){ + //video_store_data->frameNumber = captureResult; + captureResult = 0; + } + + if ( captureResult != 0 ) { + // Unable to capture image for temporary reason + // Fake a signal loss image + Rgb signalcolor; + signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */ + capture_image->Fill(signalcolor); + captureResult = 0; + } else { + captureResult = 1; + } + + if ( captureResult == 1 ) { + /* Deinterlacing */ if ( (deinterlacing & 0xff) == 1 ) { capture_image->Deinterlace_Discard(); @@ -3150,159 +3109,146 @@ int Monitor::Capture() } else if ( (deinterlacing & 0xff) == 5 ) { capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); } - - - if ( orientation != ROTATE_0 ) - { - switch ( orientation ) - { - case ROTATE_0 : - { - // No action required - break; - } - case ROTATE_90 : - case ROTATE_180 : - case ROTATE_270 : - { - capture_image->Rotate( (orientation-1)*90 ); - break; - } - case FLIP_HORI : - case FLIP_VERT : - { - capture_image->Flip( orientation==FLIP_HORI ); - break; - } - } - } + + + if ( orientation != ROTATE_0 ) { + switch ( orientation ) { + case ROTATE_0 : { + // No action required + break; + } + case ROTATE_90 : + case ROTATE_180 : + case ROTATE_270 : { + capture_image->Rotate( (orientation-1)*90 ); + break; + } + case FLIP_HORI : + case FLIP_VERT : { + capture_image->Flip( orientation==FLIP_HORI ); + break; + } + } + } + } // end if captureResults == 1 - } - if ( true ) { + // if true? let's get rid of this. + if ( true ) { - if ( capture_image->Size() > camera->ImageSize() ) - { - Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); - return( -1 ); - } + if ( capture_image->Size() > camera->ImageSize() ) { + Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); + return( -1 ); + } - if ( ((unsigned int)index == shared_data->last_read_index) && (function > MONITOR) ) - { - Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); - time_t now = time(0); - double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); - time_t last_read_delta = now - shared_data->last_read_time; - if ( last_read_delta > (image_buffer_count/approxFps) ) - { - Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) - shared_data->last_read_index = image_buffer_count; - } - } + if ( ((unsigned int)index == shared_data->last_read_index) && (function > MONITOR) ) { + Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); + time_t now = time(0); + double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); + time_t last_read_delta = now - shared_data->last_read_time; + if ( last_read_delta > (image_buffer_count/approxFps) ) { + Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) + shared_data->last_read_index = image_buffer_count; + } + } - if ( privacy_bitmask ) - capture_image->MaskPrivacy( privacy_bitmask ); + if ( privacy_bitmask ) + capture_image->MaskPrivacy( privacy_bitmask ); - gettimeofday( image_buffer[index].timestamp, NULL ); - if ( config.timestamp_on_capture ) - { - TimestampImage( capture_image, image_buffer[index].timestamp ); - } - shared_data->signal = CheckSignal(capture_image); - shared_data->last_write_index = index; - shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; + gettimeofday( image_buffer[index].timestamp, NULL ); + if ( config.timestamp_on_capture ) { + TimestampImage( capture_image, image_buffer[index].timestamp ); + } + shared_data->signal = CheckSignal(capture_image); + shared_data->last_write_index = index; + shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; - image_count++; + image_count++; - if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) - { - time_t now = image_buffer[index].timestamp->tv_sec; - fps = double(fps_report_interval)/(now-last_fps_time); - //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); - //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); - last_fps_time = now; - } + if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { + time_t now = image_buffer[index].timestamp->tv_sec; + fps = double(fps_report_interval)/(now-last_fps_time); + //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); + //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); + Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); + last_fps_time = now; + } - if ( shared_data->action & GET_SETTINGS ) - { - shared_data->brightness = camera->Brightness(); - shared_data->hue = camera->Hue(); - shared_data->colour = camera->Colour(); - shared_data->contrast = camera->Contrast(); - shared_data->action &= ~GET_SETTINGS; - } - if ( shared_data->action & SET_SETTINGS ) - { - camera->Brightness( shared_data->brightness ); - camera->Hue( shared_data->hue ); - camera->Colour( shared_data->colour ); - camera->Contrast( shared_data->contrast ); - shared_data->action &= ~SET_SETTINGS; - } - return( 0 ); - } - shared_data->signal = false; - return( -1 ); + if ( shared_data->action & GET_SETTINGS ) { + shared_data->brightness = camera->Brightness(); + shared_data->hue = camera->Hue(); + shared_data->colour = camera->Colour(); + shared_data->contrast = camera->Contrast(); + shared_data->action &= ~GET_SETTINGS; + } + if ( shared_data->action & SET_SETTINGS ) { + camera->Brightness( shared_data->brightness ); + camera->Hue( shared_data->hue ); + camera->Colour( shared_data->colour ); + camera->Contrast( shared_data->contrast ); + shared_data->action &= ~SET_SETTINGS; + } + return( 0 ); + } + shared_data->signal = false; + return( -1 ); } void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const { - if ( label_format[0] ) - { - // Expand the strftime macros first - char label_time_text[256]; - strftime( label_time_text, sizeof(label_time_text), label_format, localtime( &ts_time->tv_sec ) ); + if ( label_format[0] ) + { + // Expand the strftime macros first + char label_time_text[256]; + strftime( label_time_text, sizeof(label_time_text), label_format, localtime( &ts_time->tv_sec ) ); - char label_text[1024]; - const char *s_ptr = label_time_text; - char *d_ptr = label_text; - while ( *s_ptr && ((d_ptr-label_text) < (unsigned int)sizeof(label_text)) ) - { - if ( *s_ptr == '%' ) - { - bool found_macro = false; - switch ( *(s_ptr+1) ) - { - case 'N' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name ); - found_macro = true; - break; - case 'Q' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext ); - found_macro = true; - break; - case 'f' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000 ); - found_macro = true; - break; - } - if ( found_macro ) - { - s_ptr += 2; - continue; - } - } - *d_ptr++ = *s_ptr++; - } - *d_ptr = '\0'; - ts_image->Annotate( label_text, label_coord, label_size ); - } + char label_text[1024]; + const char *s_ptr = label_time_text; + char *d_ptr = label_text; + while ( *s_ptr && ((d_ptr-label_text) < (unsigned int)sizeof(label_text)) ) + { + if ( *s_ptr == '%' ) + { + bool found_macro = false; + switch ( *(s_ptr+1) ) + { + case 'N' : + d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name ); + found_macro = true; + break; + case 'Q' : + d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext ); + found_macro = true; + break; + case 'f' : + d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000 ); + found_macro = true; + break; + } + if ( found_macro ) + { + s_ptr += 2; + continue; + } + } + *d_ptr++ = *s_ptr++; + } + *d_ptr = '\0'; + ts_image->Annotate( label_text, label_coord, label_size ); + } } bool Monitor::closeEvent() { - video_store_data->recording = false; - if ( event ) - { - if ( function == RECORD || function == MOCORD ) - { - gettimeofday( &(event->EndTime()), NULL ); - } - delete event; - event = 0; - return( true ); - } - return( false ); + video_store_data->recording = false; + if ( event ) { + if ( function == RECORD || function == MOCORD ) { + gettimeofday( &(event->EndTime()), NULL ); + } + delete event; + event = 0; + return( true ); + } + return( false ); } //----------------------------------------- @@ -3338,151 +3284,151 @@ bool Monitor::closeEvent() /* bool Monitor::OurCheckAlarms( Zone *zone, const Image *pImage ) { - Info("Entering OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - unsigned char black_thr = 23; - int min_alarm_score = 10; - int max_alarm_score = 99; - //bool alarm = false; - unsigned int score; - Polygon zone_polygon = zone->GetPolygon(); - Info("Got polygon of a zone. It has %d vertices.", zone_polygon.getNumCoords()); + Info("Entering OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + unsigned char black_thr = 23; + int min_alarm_score = 10; + int max_alarm_score = 99; + //bool alarm = false; + unsigned int score; + Polygon zone_polygon = zone->GetPolygon(); + Info("Got polygon of a zone. It has %d vertices.", zone_polygon.getNumCoords()); zone->ResetStats(); - Info("ResetStats done."); + Info("ResetStats done."); - if ( !zone->CheckOverloadCount() ) - { - Info("CheckOverloadCount() return false, we'll return false."); - return( false ); - } + if ( !zone->CheckOverloadCount() ) + { + Info("CheckOverloadCount() return false, we'll return false."); + return( false ); + } - Image *pMaskImage = new Image(pImage->Width(), pImage->Height(), ZM_COLOUR_GRAY8, pImage->SubpixelOrder()); - Info("Mask image created."); + Image *pMaskImage = new Image(pImage->Width(), pImage->Height(), ZM_COLOUR_GRAY8, pImage->SubpixelOrder()); + Info("Mask image created."); - pMaskImage->Fill(BLACK); - Info("Mask image filled with BLACK."); - if (pImage->Colours() == ZM_COLOUR_GRAY8) - { - Info("Analysed image is not colored! Set score = 0."); - score = 0; - } - else - { - Info("Start processing image."); - //Process image - unsigned char *buffer = (unsigned char*)pImage->Buffer(); - unsigned char *mask_buffer = (unsigned char*)pMaskImage->Buffer(); - - int black_pixels_count = 0; - Info("Loop for black pixels counting and mask filling."); - while (buffer < (pImage->Buffer() + pImage->Size())) - { - if ( (RED(buffer) < black_thr) && (GREEN(buffer) < black_thr) && (BLUE(buffer) < black_thr) ) - { - *mask_buffer = WHITE; - black_pixels_count++; - } - buffer += pImage->Colours(); - mask_buffer++; - } + pMaskImage->Fill(BLACK); + Info("Mask image filled with BLACK."); + if (pImage->Colours() == ZM_COLOUR_GRAY8) + { + Info("Analysed image is not colored! Set score = 0."); + score = 0; + } + else + { + Info("Start processing image."); + //Process image + unsigned char *buffer = (unsigned char*)pImage->Buffer(); + unsigned char *mask_buffer = (unsigned char*)pMaskImage->Buffer(); + + int black_pixels_count = 0; + Info("Loop for black pixels counting and mask filling."); + while (buffer < (pImage->Buffer() + pImage->Size())) + { + if ( (RED(buffer) < black_thr) && (GREEN(buffer) < black_thr) && (BLUE(buffer) < black_thr) ) + { + *mask_buffer = WHITE; + black_pixels_count++; + } + buffer += pImage->Colours(); + mask_buffer++; + } - if ( !black_pixels_count ) - { - delete pMaskImage; - return( false ); - } - score = (100*black_pixels_count)/zone_polygon.Area(); - Info("Number of black pixels is %d, zone polygon area is %d, score is %d", black_pixels_count, zone_polygon.Area(), score); + if ( !black_pixels_count ) + { + delete pMaskImage; + return( false ); + } + score = (100*black_pixels_count)/zone_polygon.Area(); + Info("Number of black pixels is %d, zone polygon area is %d, score is %d", black_pixels_count, zone_polygon.Area(), score); - if ( min_alarm_score && ( score < min_alarm_score) ) - { - delete pMaskImage; - return( false ); - } - if ( max_alarm_score && (score > max_alarm_score) ) - { - zone->SetOverloadCount(zone->GetOverloadFrames()); - delete pMaskImage; - return( false ); - } - } + if ( min_alarm_score && ( score < min_alarm_score) ) + { + delete pMaskImage; + return( false ); + } + if ( max_alarm_score && (score > max_alarm_score) ) + { + zone->SetOverloadCount(zone->GetOverloadFrames()); + delete pMaskImage; + return( false ); + } + } - zone->SetScore(score); - Info("Score have been set in zone."); - //Get mask - Rgb alarm_colour = RGB_RED; + zone->SetScore(score); + Info("Score have been set in zone."); + //Get mask + Rgb alarm_colour = RGB_RED; Image *tempImage = pMaskImage->HighlightEdges(alarm_colour, &zone_polygon.Extent() ); - Info("After HighlightEdges"); + Info("After HighlightEdges"); - zone->SetAlarmImage(tempImage); - Info("After SetAlarmImage"); - delete pMaskImage; - Info("After Delete pMaskImage"); - delete tempImage; + zone->SetAlarmImage(tempImage); + Info("After SetAlarmImage"); + delete pMaskImage; + Info("After Delete pMaskImage"); + delete tempImage; - Info("Leaving OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - return true; + Info("Leaving OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + return true; } unsigned int Monitor::DetectBlack(const Image &comp_image, Event::StringSet &zoneSet ) { - Info("Entering DetectBlack >>>>>>>>>>>>>>>>>>>>>>>>>>"); - bool alarm = false; - unsigned int score = 0; + Info("Entering DetectBlack >>>>>>>>>>>>>>>>>>>>>>>>>>"); + bool alarm = false; + unsigned int score = 0; - if ( n_zones <= 0 ) return( alarm ); + if ( n_zones <= 0 ) return( alarm ); -// Coord alarm_centre; -// int top_score = -1; +// Coord alarm_centre; +// int top_score = -1; - // Find all alarm pixels in active zones - Info("Number of zones to process %d", n_zones); - for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) - { - Zone *zone = zones[n_zone]; - if ( !zone->IsActive() ) - { - continue; - } - Debug( 3, "Checking active zone %s", zone->Label() ); - Info( "Checking active zone %s", zone->Label() ); - if ( OurCheckAlarms( zone, &comp_image ) ) - { - Info("OurCheckAlarm is TRUE!!!!!!"); - alarm = true; - score += zone->Score(); - zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - Info( "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); -// if ( config.opt_control && track_motion ) -// { -// if ( (int)zone->Score() > top_score ) -// { -// top_score = zone->Score(); -// alarm_centre = zone->GetAlarmCentre(); -// } -// } - } - Info( "Finish checking active zone %s", zone->Label() ); - } + // Find all alarm pixels in active zones + Info("Number of zones to process %d", n_zones); + for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) + { + Zone *zone = zones[n_zone]; + if ( !zone->IsActive() ) + { + continue; + } + Debug( 3, "Checking active zone %s", zone->Label() ); + Info( "Checking active zone %s", zone->Label() ); + if ( OurCheckAlarms( zone, &comp_image ) ) + { + Info("OurCheckAlarm is TRUE!!!!!!"); + alarm = true; + score += zone->Score(); + zone->SetAlarm(); + Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); + Info( "Zone is alarmed, zone score = %d", zone->Score() ); + zoneSet.insert( zone->Label() ); +// if ( config.opt_control && track_motion ) +// { +// if ( (int)zone->Score() > top_score ) +// { +// top_score = zone->Score(); +// alarm_centre = zone->GetAlarmCentre(); +// } +// } + } + Info( "Finish checking active zone %s", zone->Label() ); + } -// if ( top_score > 0 ) -// { -// shared_data->alarm_x = alarm_centre.X(); -// shared_data->alarm_y = alarm_centre.Y(); +// if ( top_score > 0 ) +// { +// shared_data->alarm_x = alarm_centre.X(); +// shared_data->alarm_y = alarm_centre.Y(); // -// Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count ); -// } -// else -// { -// shared_data->alarm_x = shared_data->alarm_y = -1; -// } +// Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count ); +// } +// else +// { +// shared_data->alarm_x = shared_data->alarm_y = -1; +// } - // This is a small and innocent hack to prevent scores of 0 being returned in alarm state - Info("Leaving DetectBlack <<<<<<<<<<<<<<<<<<<<<<<<<<<"); - return( score?score:alarm ); + // This is a small and innocent hack to prevent scores of 0 being returned in alarm state + Info("Leaving DetectBlack <<<<<<<<<<<<<<<<<<<<<<<<<<<"); + return( score?score:alarm ); } */ @@ -3492,785 +3438,785 @@ unsigned int Monitor::DetectBlack(const Image &comp_image, Event::StringSet &zon unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet ) { - bool alarm = false; - unsigned int score = 0; + bool alarm = false; + unsigned int score = 0; - if ( n_zones <= 0 ) return( alarm ); + if ( n_zones <= 0 ) return( alarm ); - if ( config.record_diag_images ) - { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) - { - snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", config.dir_events, id ); - } - ref_image.WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + { + static char diag_path[PATH_MAX] = ""; + if ( !diag_path[0] ) + { + snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", config.dir_events, id ); + } + ref_image.WriteJpeg( diag_path ); + } - ref_image.Delta( comp_image, &delta_image); + ref_image.Delta( comp_image, &delta_image); - if ( config.record_diag_images ) - { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) - { - snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", config.dir_events, id ); - } - delta_image.WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + { + static char diag_path[PATH_MAX] = ""; + if ( !diag_path[0] ) + { + snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", config.dir_events, id ); + } + delta_image.WriteJpeg( diag_path ); + } - // Blank out all exclusion zones - for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) - { - Zone *zone = zones[n_zone]; - // need previous alarmed state for preclusive zone, so don't clear just yet - if (!zone->IsPreclusive()) - zone->ClearAlarm(); - if ( !zone->IsInactive() ) - { - continue; - } - Debug( 3, "Blanking inactive zone %s", zone->Label() ); - delta_image.Fill( RGB_BLACK, zone->GetPolygon() ); - } + // Blank out all exclusion zones + for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) + { + Zone *zone = zones[n_zone]; + // need previous alarmed state for preclusive zone, so don't clear just yet + if (!zone->IsPreclusive()) + zone->ClearAlarm(); + if ( !zone->IsInactive() ) + { + continue; + } + Debug( 3, "Blanking inactive zone %s", zone->Label() ); + delta_image.Fill( RGB_BLACK, zone->GetPolygon() ); + } - // Check preclusive zones first - for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) - { - Zone *zone = zones[n_zone]; - if ( !zone->IsPreclusive() ) - { - continue; - } - int old_zone_score = zone->Score(); - bool old_zone_alarmed = zone->Alarmed(); - Debug( 3, "Checking preclusive zone %s - old score: %d, state: %s", zone->Label(),old_zone_score, zone->Alarmed()?"alarmed":"quiet" ); - if ( zone->CheckAlarms( &delta_image ) ) - { - alarm = true; - score += zone->Score(); - zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); - //zone->ResetStats(); - } else { - // check if end of alarm - if (old_zone_alarmed) { - Debug(3, "Preclusive Zone %s alarm Ends. Prevíous score: %d", zone->Label(), old_zone_score); - if (old_zone_score > 0) { - zone->SetExtendAlarmCount(zone->GetExtendAlarmFrames()); - } - if (zone->CheckExtendAlarmCount()) { - alarm=true; - zone->SetAlarm(); - } else { - zone->ClearAlarm(); - } - } - } - } + // Check preclusive zones first + for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) + { + Zone *zone = zones[n_zone]; + if ( !zone->IsPreclusive() ) + { + continue; + } + int old_zone_score = zone->Score(); + bool old_zone_alarmed = zone->Alarmed(); + Debug( 3, "Checking preclusive zone %s - old score: %d, state: %s", zone->Label(),old_zone_score, zone->Alarmed()?"alarmed":"quiet" ); + if ( zone->CheckAlarms( &delta_image ) ) + { + alarm = true; + score += zone->Score(); + zone->SetAlarm(); + Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); + zoneSet.insert( zone->Label() ); + //zone->ResetStats(); + } else { + // check if end of alarm + if (old_zone_alarmed) { + Debug(3, "Preclusive Zone %s alarm Ends. Prevíous score: %d", zone->Label(), old_zone_score); + if (old_zone_score > 0) { + zone->SetExtendAlarmCount(zone->GetExtendAlarmFrames()); + } + if (zone->CheckExtendAlarmCount()) { + alarm=true; + zone->SetAlarm(); + } else { + zone->ClearAlarm(); + } + } + } + } - Coord alarm_centre; - int top_score = -1; + Coord alarm_centre; + int top_score = -1; - if ( alarm ) - { - alarm = false; - score = 0; - } - else - { - // Find all alarm pixels in active zones - for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) - { - Zone *zone = zones[n_zone]; - if ( !zone->IsActive() || zone->IsPreclusive()) - { - continue; - } - Debug( 3, "Checking active zone %s", zone->Label() ); - if ( zone->CheckAlarms( &delta_image ) ) - { - alarm = true; - score += zone->Score(); - zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); - if ( config.opt_control && track_motion ) - { - if ( (int)zone->Score() > top_score ) - { - top_score = zone->Score(); - alarm_centre = zone->GetAlarmCentre(); - } - } - } - } + if ( alarm ) + { + alarm = false; + score = 0; + } + else + { + // Find all alarm pixels in active zones + for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) + { + Zone *zone = zones[n_zone]; + if ( !zone->IsActive() || zone->IsPreclusive()) + { + continue; + } + Debug( 3, "Checking active zone %s", zone->Label() ); + if ( zone->CheckAlarms( &delta_image ) ) + { + alarm = true; + score += zone->Score(); + zone->SetAlarm(); + Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); + zoneSet.insert( zone->Label() ); + if ( config.opt_control && track_motion ) + { + if ( (int)zone->Score() > top_score ) + { + top_score = zone->Score(); + alarm_centre = zone->GetAlarmCentre(); + } + } + } + } - if ( alarm ) - { - for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) - { - Zone *zone = zones[n_zone]; - if ( !zone->IsInclusive() ) - { - continue; - } - Debug( 3, "Checking inclusive zone %s", zone->Label() ); - if ( zone->CheckAlarms( &delta_image ) ) - { - alarm = true; - score += zone->Score(); - zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); - if ( config.opt_control && track_motion ) - { - if ( zone->Score() > (unsigned int)top_score ) - { - top_score = zone->Score(); - alarm_centre = zone->GetAlarmCentre(); - } - } - } - } - } - else - { - // Find all alarm pixels in exclusive zones - for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) - { - Zone *zone = zones[n_zone]; - if ( !zone->IsExclusive() ) - { - continue; - } - Debug( 3, "Checking exclusive zone %s", zone->Label() ); - if ( zone->CheckAlarms( &delta_image ) ) - { - alarm = true; - score += zone->Score(); - zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); - } - } - } - } + if ( alarm ) + { + for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) + { + Zone *zone = zones[n_zone]; + if ( !zone->IsInclusive() ) + { + continue; + } + Debug( 3, "Checking inclusive zone %s", zone->Label() ); + if ( zone->CheckAlarms( &delta_image ) ) + { + alarm = true; + score += zone->Score(); + zone->SetAlarm(); + Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); + zoneSet.insert( zone->Label() ); + if ( config.opt_control && track_motion ) + { + if ( zone->Score() > (unsigned int)top_score ) + { + top_score = zone->Score(); + alarm_centre = zone->GetAlarmCentre(); + } + } + } + } + } + else + { + // Find all alarm pixels in exclusive zones + for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) + { + Zone *zone = zones[n_zone]; + if ( !zone->IsExclusive() ) + { + continue; + } + Debug( 3, "Checking exclusive zone %s", zone->Label() ); + if ( zone->CheckAlarms( &delta_image ) ) + { + alarm = true; + score += zone->Score(); + zone->SetAlarm(); + Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); + zoneSet.insert( zone->Label() ); + } + } + } + } - if ( top_score > 0 ) - { - shared_data->alarm_x = alarm_centre.X(); - shared_data->alarm_y = alarm_centre.Y(); + if ( top_score > 0 ) + { + shared_data->alarm_x = alarm_centre.X(); + shared_data->alarm_y = alarm_centre.Y(); - Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count ); - } - else - { - shared_data->alarm_x = shared_data->alarm_y = -1; - } + Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count ); + } + else + { + shared_data->alarm_x = shared_data->alarm_y = -1; + } - // This is a small and innocent hack to prevent scores of 0 being returned in alarm state - return( score?score:alarm ); + // This is a small and innocent hack to prevent scores of 0 being returned in alarm state + return( score?score:alarm ); } bool Monitor::DumpSettings( char *output, bool verbose ) { - output[0] = 0; + output[0] = 0; - sprintf( output+strlen(output), "Id : %d\n", id ); - sprintf( output+strlen(output), "Name : %s\n", name ); - sprintf( output+strlen(output), "Type : %s\n", camera->IsLocal()?"Local":(camera->IsRemote()?"Remote":"File") ); + sprintf( output+strlen(output), "Id : %d\n", id ); + sprintf( output+strlen(output), "Name : %s\n", name ); + sprintf( output+strlen(output), "Type : %s\n", camera->IsLocal()?"Local":(camera->IsRemote()?"Remote":"File") ); #if ZM_HAS_V4L - if ( camera->IsLocal() ) - { - sprintf( output+strlen(output), "Device : %s\n", ((LocalCamera *)camera)->Device().c_str() ); - sprintf( output+strlen(output), "Channel : %d\n", ((LocalCamera *)camera)->Channel() ); - sprintf( output+strlen(output), "Standard : %d\n", ((LocalCamera *)camera)->Standard() ); - } - else + if ( camera->IsLocal() ) + { + sprintf( output+strlen(output), "Device : %s\n", ((LocalCamera *)camera)->Device().c_str() ); + sprintf( output+strlen(output), "Channel : %d\n", ((LocalCamera *)camera)->Channel() ); + sprintf( output+strlen(output), "Standard : %d\n", ((LocalCamera *)camera)->Standard() ); + } + else #endif // ZM_HAS_V4L - if ( camera->IsRemote() ) - { - sprintf( output+strlen(output), "Protocol : %s\n", ((RemoteCamera *)camera)->Protocol().c_str() ); - sprintf( output+strlen(output), "Host : %s\n", ((RemoteCamera *)camera)->Host().c_str() ); - sprintf( output+strlen(output), "Port : %s\n", ((RemoteCamera *)camera)->Port().c_str() ); - sprintf( output+strlen(output), "Path : %s\n", ((RemoteCamera *)camera)->Path().c_str() ); - } - else if ( camera->IsFile() ) - { - sprintf( output+strlen(output), "Path : %s\n", ((FileCamera *)camera)->Path() ); - } + if ( camera->IsRemote() ) + { + sprintf( output+strlen(output), "Protocol : %s\n", ((RemoteCamera *)camera)->Protocol().c_str() ); + sprintf( output+strlen(output), "Host : %s\n", ((RemoteCamera *)camera)->Host().c_str() ); + sprintf( output+strlen(output), "Port : %s\n", ((RemoteCamera *)camera)->Port().c_str() ); + sprintf( output+strlen(output), "Path : %s\n", ((RemoteCamera *)camera)->Path().c_str() ); + } + else if ( camera->IsFile() ) + { + sprintf( output+strlen(output), "Path : %s\n", ((FileCamera *)camera)->Path() ); + } #if HAVE_LIBAVFORMAT - else if ( camera->IsFfmpeg() ) - { - sprintf( output+strlen(output), "Path : %s\n", ((FfmpegCamera *)camera)->Path().c_str() ); - } + else if ( camera->IsFfmpeg() ) + { + sprintf( output+strlen(output), "Path : %s\n", ((FfmpegCamera *)camera)->Path().c_str() ); + } #endif // HAVE_LIBAVFORMAT - sprintf( output+strlen(output), "Width : %d\n", camera->Width() ); - sprintf( output+strlen(output), "Height : %d\n", camera->Height() ); + sprintf( output+strlen(output), "Width : %d\n", camera->Width() ); + sprintf( output+strlen(output), "Height : %d\n", camera->Height() ); #if ZM_HAS_V4L - if ( camera->IsLocal() ) - { - sprintf( output+strlen(output), "Palette : %d\n", ((LocalCamera *)camera)->Palette() ); - } + if ( camera->IsLocal() ) + { + sprintf( output+strlen(output), "Palette : %d\n", ((LocalCamera *)camera)->Palette() ); + } #endif // ZM_HAS_V4L - sprintf( output+strlen(output), "Colours : %d\n", camera->Colours() ); - sprintf( output+strlen(output), "Subpixel Order : %d\n", camera->SubpixelOrder() ); - sprintf( output+strlen(output), "Event Prefix : %s\n", event_prefix ); - sprintf( output+strlen(output), "Label Format : %s\n", label_format ); - sprintf( output+strlen(output), "Label Coord : %d,%d\n", label_coord.X(), label_coord.Y() ); - sprintf( output+strlen(output), "Label Size : %d\n", label_size ); - sprintf( output+strlen(output), "Image Buffer Count : %d\n", image_buffer_count ); - sprintf( output+strlen(output), "Warmup Count : %d\n", warmup_count ); - sprintf( output+strlen(output), "Pre Event Count : %d\n", pre_event_count ); - sprintf( output+strlen(output), "Post Event Count : %d\n", post_event_count ); - sprintf( output+strlen(output), "Stream Replay Buffer : %d\n", stream_replay_buffer ); - sprintf( output+strlen(output), "Alarm Frame Count : %d\n", alarm_frame_count ); - sprintf( output+strlen(output), "Section Length : %d\n", section_length ); - sprintf( output+strlen(output), "Maximum FPS : %.2f\n", capture_delay?DT_PREC_3/capture_delay:0.0 ); - sprintf( output+strlen(output), "Alarm Maximum FPS : %.2f\n", alarm_capture_delay?DT_PREC_3/alarm_capture_delay:0.0 ); - sprintf( output+strlen(output), "Reference Blend %%ge : %d\n", ref_blend_perc ); - sprintf( output+strlen(output), "Alarm Reference Blend %%ge : %d\n", alarm_ref_blend_perc ); - sprintf( output+strlen(output), "Track Motion : %d\n", track_motion ); - sprintf( output+strlen(output), "Function: %d - %s\n", function, - function==NONE?"None":( - function==MONITOR?"Monitor Only":( - function==MODECT?"Motion Detection":( - function==RECORD?"Continuous Record":( - function==MOCORD?"Continuous Record with Motion Detection":( - function==NODECT?"Externally Triggered only, no Motion Detection":"Unknown" - )))))); - sprintf( output+strlen(output), "Zones : %d\n", n_zones ); - for ( int i = 0; i < n_zones; i++ ) - { - zones[i]->DumpSettings( output+strlen(output), verbose ); - } - return( true ); -} + sprintf( output+strlen(output), "Colours : %d\n", camera->Colours() ); + sprintf( output+strlen(output), "Subpixel Order : %d\n", camera->SubpixelOrder() ); + sprintf( output+strlen(output), "Event Prefix : %s\n", event_prefix ); + sprintf( output+strlen(output), "Label Format : %s\n", label_format ); + sprintf( output+strlen(output), "Label Coord : %d,%d\n", label_coord.X(), label_coord.Y() ); + sprintf( output+strlen(output), "Label Size : %d\n", label_size ); + sprintf( output+strlen(output), "Image Buffer Count : %d\n", image_buffer_count ); + sprintf( output+strlen(output), "Warmup Count : %d\n", warmup_count ); + sprintf( output+strlen(output), "Pre Event Count : %d\n", pre_event_count ); + sprintf( output+strlen(output), "Post Event Count : %d\n", post_event_count ); + sprintf( output+strlen(output), "Stream Replay Buffer : %d\n", stream_replay_buffer ); + sprintf( output+strlen(output), "Alarm Frame Count : %d\n", alarm_frame_count ); + sprintf( output+strlen(output), "Section Length : %d\n", section_length ); + sprintf( output+strlen(output), "Maximum FPS : %.2f\n", capture_delay?DT_PREC_3/capture_delay:0.0 ); + sprintf( output+strlen(output), "Alarm Maximum FPS : %.2f\n", alarm_capture_delay?DT_PREC_3/alarm_capture_delay:0.0 ); + sprintf( output+strlen(output), "Reference Blend %%ge : %d\n", ref_blend_perc ); + sprintf( output+strlen(output), "Alarm Reference Blend %%ge : %d\n", alarm_ref_blend_perc ); + sprintf( output+strlen(output), "Track Motion : %d\n", track_motion ); + sprintf( output+strlen(output), "Function: %d - %s\n", function, + function==NONE?"None":( + function==MONITOR?"Monitor Only":( + function==MODECT?"Motion Detection":( + function==RECORD?"Continuous Record":( + function==MOCORD?"Continuous Record with Motion Detection":( + function==NODECT?"Externally Triggered only, no Motion Detection":"Unknown" + )))))); + sprintf( output+strlen(output), "Zones : %d\n", n_zones ); + for ( int i = 0; i < n_zones; i++ ) + { + zones[i]->DumpSettings( output+strlen(output), verbose ); + } + return( true ); +} // bool Monitor::DumpSettings( char *output, bool verbose ) bool MonitorStream::checkSwapPath( const char *path, bool create_path ) { - uid_t uid = getuid(); - gid_t gid = getgid(); + uid_t uid = getuid(); + gid_t gid = getgid(); - struct stat stat_buf; - if ( stat( path, &stat_buf ) < 0 ) - { - if ( create_path && errno == ENOENT ) - { - Debug( 3, "Swap path '%s' missing, creating", path ); - if ( mkdir( path, 0755 ) ) - { - Error( "Can't mkdir %s: %s", path, strerror(errno)); - return( false ); - } - if ( stat( path, &stat_buf ) < 0 ) - { - Error( "Can't stat '%s': %s", path, strerror(errno) ); - return( false ); - } - } - else - { - Error( "Can't stat '%s': %s", path, strerror(errno) ); - return( false ); - } - } - if ( !S_ISDIR(stat_buf.st_mode) ) - { - Error( "Swap image path '%s' is not a directory", path ); - return( false ); - } + struct stat stat_buf; + if ( stat( path, &stat_buf ) < 0 ) + { + if ( create_path && errno == ENOENT ) + { + Debug( 3, "Swap path '%s' missing, creating", path ); + if ( mkdir( path, 0755 ) ) + { + Error( "Can't mkdir %s: %s", path, strerror(errno)); + return( false ); + } + if ( stat( path, &stat_buf ) < 0 ) + { + Error( "Can't stat '%s': %s", path, strerror(errno) ); + return( false ); + } + } + else + { + Error( "Can't stat '%s': %s", path, strerror(errno) ); + return( false ); + } + } + if ( !S_ISDIR(stat_buf.st_mode) ) + { + Error( "Swap image path '%s' is not a directory", path ); + return( false ); + } - mode_t mask = 0; - if ( uid == stat_buf.st_uid ) - { - // If we are the owner - mask = 00700; - } - else if ( gid == stat_buf.st_gid ) - { - // If we are in the owner group - mask = 00070; - } - else - { - // We are neither the owner nor in the group - mask = 00007; - } + mode_t mask = 0; + if ( uid == stat_buf.st_uid ) + { + // If we are the owner + mask = 00700; + } + else if ( gid == stat_buf.st_gid ) + { + // If we are in the owner group + mask = 00070; + } + else + { + // We are neither the owner nor in the group + mask = 00007; + } - if ( (stat_buf.st_mode & mask) != mask ) - { - Error( "Insufficient permissions on swap image path '%s'", path ); - return( false ); - } - return( true ); + if ( (stat_buf.st_mode & mask) != mask ) + { + Error( "Insufficient permissions on swap image path '%s'", path ); + return( false ); + } + return( true ); } void MonitorStream::processCommand( const CmdMsg *msg ) { - Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ); - // Check for incoming command - switch( (MsgCommand)msg->msg_data[0] ) - { - case CMD_PAUSE : - { - Debug( 1, "Got PAUSE command" ); + Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ); + // Check for incoming command + switch( (MsgCommand)msg->msg_data[0] ) + { + case CMD_PAUSE : + { + Debug( 1, "Got PAUSE command" ); - // Set paused flag - paused = true; - // Set delayed flag - delayed = true; - last_frame_sent = TV_2_FLOAT( now ); - break; - } - case CMD_PLAY : - { - Debug( 1, "Got PLAY command" ); - if ( paused ) - { - // Clear paused flag - paused = false; - // Set delayed_play flag - delayed = true; - } - replay_rate = ZM_RATE_BASE; - break; - } - case CMD_VARPLAY : - { - Debug( 1, "Got VARPLAY command" ); - if ( paused ) - { - // Clear paused flag - paused = false; - // Set delayed_play flag - delayed = true; - } - replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768; - break; - } - case CMD_STOP : - { - Debug( 1, "Got STOP command" ); + // Set paused flag + paused = true; + // Set delayed flag + delayed = true; + last_frame_sent = TV_2_FLOAT( now ); + break; + } + case CMD_PLAY : + { + Debug( 1, "Got PLAY command" ); + if ( paused ) + { + // Clear paused flag + paused = false; + // Set delayed_play flag + delayed = true; + } + replay_rate = ZM_RATE_BASE; + break; + } + case CMD_VARPLAY : + { + Debug( 1, "Got VARPLAY command" ); + if ( paused ) + { + // Clear paused flag + paused = false; + // Set delayed_play flag + delayed = true; + } + replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768; + break; + } + case CMD_STOP : + { + Debug( 1, "Got STOP command" ); - // Clear paused flag - paused = false; - // Clear delayed_play flag - delayed = false; - break; - } - case CMD_FASTFWD : - { - Debug( 1, "Got FAST FWD command" ); - if ( paused ) - { - // Clear paused flag - paused = false; - // Set delayed_play flag - delayed = true; - } - // Set play rate - switch ( replay_rate ) - { - case 2 * ZM_RATE_BASE : - replay_rate = 5 * ZM_RATE_BASE; - break; - case 5 * ZM_RATE_BASE : - replay_rate = 10 * ZM_RATE_BASE; - break; - case 10 * ZM_RATE_BASE : - replay_rate = 25 * ZM_RATE_BASE; - break; - case 25 * ZM_RATE_BASE : - case 50 * ZM_RATE_BASE : - replay_rate = 50 * ZM_RATE_BASE; - break; - default : - replay_rate = 2 * ZM_RATE_BASE; - break; - } - break; - } - case CMD_SLOWFWD : - { - Debug( 1, "Got SLOW FWD command" ); - // Set paused flag - paused = true; - // Set delayed flag - delayed = true; - // Set play rate - replay_rate = ZM_RATE_BASE; - // Set step - step = 1; - break; - } - case CMD_SLOWREV : - { - Debug( 1, "Got SLOW REV command" ); - // Set paused flag - paused = true; - // Set delayed flag - delayed = true; - // Set play rate - replay_rate = ZM_RATE_BASE; - // Set step - step = -1; - break; - } - case CMD_FASTREV : - { - Debug( 1, "Got FAST REV command" ); - if ( paused ) - { - // Clear paused flag - paused = false; - // Set delayed_play flag - delayed = true; - } - // Set play rate - switch ( replay_rate ) - { - case -2 * ZM_RATE_BASE : - replay_rate = -5 * ZM_RATE_BASE; - break; - case -5 * ZM_RATE_BASE : - replay_rate = -10 * ZM_RATE_BASE; - break; - case -10 * ZM_RATE_BASE : - replay_rate = -25 * ZM_RATE_BASE; - break; - case -25 * ZM_RATE_BASE : - case -50 * ZM_RATE_BASE : - replay_rate = -50 * ZM_RATE_BASE; - break; - default : - replay_rate = -2 * ZM_RATE_BASE; - break; - } - break; - } - case CMD_ZOOMIN : - { - x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; - y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; - Debug( 1, "Got ZOOM IN command, to %d,%d", x, y ); - switch ( zoom ) - { - case 100: - zoom = 150; - break; - case 150: - zoom = 200; - break; - case 200: - zoom = 300; - break; - case 300: - zoom = 400; - break; - case 400: - default : - zoom = 500; - break; - } - break; - } - case CMD_ZOOMOUT : - { - Debug( 1, "Got ZOOM OUT command" ); - switch ( zoom ) - { - case 500: - zoom = 400; - break; - case 400: - zoom = 300; - break; - case 300: - zoom = 200; - break; - case 200: - zoom = 150; - break; - case 150: - default : - zoom = 100; - break; - } - break; - } - case CMD_PAN : - { - x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; - y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; - Debug( 1, "Got PAN command, to %d,%d", x, y ); - break; - } - case CMD_SCALE : - { - scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; - Debug( 1, "Got SCALE command, to %d", scale ); - break; - } + // Clear paused flag + paused = false; + // Clear delayed_play flag + delayed = false; + break; + } + case CMD_FASTFWD : + { + Debug( 1, "Got FAST FWD command" ); + if ( paused ) + { + // Clear paused flag + paused = false; + // Set delayed_play flag + delayed = true; + } + // Set play rate + switch ( replay_rate ) + { + case 2 * ZM_RATE_BASE : + replay_rate = 5 * ZM_RATE_BASE; + break; + case 5 * ZM_RATE_BASE : + replay_rate = 10 * ZM_RATE_BASE; + break; + case 10 * ZM_RATE_BASE : + replay_rate = 25 * ZM_RATE_BASE; + break; + case 25 * ZM_RATE_BASE : + case 50 * ZM_RATE_BASE : + replay_rate = 50 * ZM_RATE_BASE; + break; + default : + replay_rate = 2 * ZM_RATE_BASE; + break; + } + break; + } + case CMD_SLOWFWD : + { + Debug( 1, "Got SLOW FWD command" ); + // Set paused flag + paused = true; + // Set delayed flag + delayed = true; + // Set play rate + replay_rate = ZM_RATE_BASE; + // Set step + step = 1; + break; + } + case CMD_SLOWREV : + { + Debug( 1, "Got SLOW REV command" ); + // Set paused flag + paused = true; + // Set delayed flag + delayed = true; + // Set play rate + replay_rate = ZM_RATE_BASE; + // Set step + step = -1; + break; + } + case CMD_FASTREV : + { + Debug( 1, "Got FAST REV command" ); + if ( paused ) + { + // Clear paused flag + paused = false; + // Set delayed_play flag + delayed = true; + } + // Set play rate + switch ( replay_rate ) + { + case -2 * ZM_RATE_BASE : + replay_rate = -5 * ZM_RATE_BASE; + break; + case -5 * ZM_RATE_BASE : + replay_rate = -10 * ZM_RATE_BASE; + break; + case -10 * ZM_RATE_BASE : + replay_rate = -25 * ZM_RATE_BASE; + break; + case -25 * ZM_RATE_BASE : + case -50 * ZM_RATE_BASE : + replay_rate = -50 * ZM_RATE_BASE; + break; + default : + replay_rate = -2 * ZM_RATE_BASE; + break; + } + break; + } + case CMD_ZOOMIN : + { + x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; + y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; + Debug( 1, "Got ZOOM IN command, to %d,%d", x, y ); + switch ( zoom ) + { + case 100: + zoom = 150; + break; + case 150: + zoom = 200; + break; + case 200: + zoom = 300; + break; + case 300: + zoom = 400; + break; + case 400: + default : + zoom = 500; + break; + } + break; + } + case CMD_ZOOMOUT : + { + Debug( 1, "Got ZOOM OUT command" ); + switch ( zoom ) + { + case 500: + zoom = 400; + break; + case 400: + zoom = 300; + break; + case 300: + zoom = 200; + break; + case 200: + zoom = 150; + break; + case 150: + default : + zoom = 100; + break; + } + break; + } + case CMD_PAN : + { + x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; + y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; + Debug( 1, "Got PAN command, to %d,%d", x, y ); + break; + } + case CMD_SCALE : + { + scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; + Debug( 1, "Got SCALE command, to %d", scale ); + break; + } case CMD_QUIT : { Info ("User initiated exit - CMD_QUIT"); break; } - case CMD_QUERY : - { - Debug( 1, "Got QUERY command, sending STATUS" ); - break; - } - default : - { - Error( "Got unexpected command %d", msg->msg_data[0] ); - break; - } - } + case CMD_QUERY : + { + Debug( 1, "Got QUERY command, sending STATUS" ); + break; + } + default : + { + Error( "Got unexpected command %d", msg->msg_data[0] ); + break; + } + } - struct { - int id; - int state; - double fps; - int buffer_level; - int rate; - double delay; - int zoom; - bool delayed; - bool paused; - bool enabled; - bool forced; - } status_data; + struct { + int id; + int state; + double fps; + int buffer_level; + int rate; + double delay; + int zoom; + bool delayed; + bool paused; + bool enabled; + bool forced; + } status_data; - status_data.id = monitor->Id(); - status_data.fps = monitor->GetFPS(); - status_data.state = monitor->shared_data->state; - if ( playback_buffer > 0 ) - status_data.buffer_level = (MOD_ADD( (temp_write_index-temp_read_index), 0, temp_image_buffer_count )*100)/temp_image_buffer_count; - else - status_data.buffer_level = 0; - status_data.delayed = delayed; - status_data.paused = paused; - status_data.rate = replay_rate; - status_data.delay = TV_2_FLOAT( now ) - TV_2_FLOAT( last_frame_timestamp ); - status_data.zoom = zoom; - //status_data.enabled = monitor->shared_data->active; - status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF; - status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON; - Debug( 2, "L:%d, D:%d, P:%d, R:%d, d:%.3f, Z:%d, E:%d F:%d", - status_data.buffer_level, - status_data.delayed, - status_data.paused, - status_data.rate, - status_data.delay, - status_data.zoom, - status_data.enabled, - status_data.forced - ); + status_data.id = monitor->Id(); + status_data.fps = monitor->GetFPS(); + status_data.state = monitor->shared_data->state; + if ( playback_buffer > 0 ) + status_data.buffer_level = (MOD_ADD( (temp_write_index-temp_read_index), 0, temp_image_buffer_count )*100)/temp_image_buffer_count; + else + status_data.buffer_level = 0; + status_data.delayed = delayed; + status_data.paused = paused; + status_data.rate = replay_rate; + status_data.delay = TV_2_FLOAT( now ) - TV_2_FLOAT( last_frame_timestamp ); + status_data.zoom = zoom; + //status_data.enabled = monitor->shared_data->active; + status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF; + status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON; + Debug( 2, "L:%d, D:%d, P:%d, R:%d, d:%.3f, Z:%d, E:%d F:%d", + status_data.buffer_level, + status_data.delayed, + status_data.paused, + status_data.rate, + status_data.delay, + status_data.zoom, + status_data.enabled, + status_data.forced + ); - DataMsg status_msg; - status_msg.msg_type = MSG_DATA_WATCH; - memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) ); - int nbytes = 0; - if ( (nbytes = sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) )) < 0 ) - { - //if ( errno != EAGAIN ) - { - Error( "Can't sendto on sd %d: %s", sd, strerror(errno) ); - //exit( -1 ); - } - } + DataMsg status_msg; + status_msg.msg_type = MSG_DATA_WATCH; + memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) ); + int nbytes = 0; + if ( (nbytes = sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) )) < 0 ) + { + //if ( errno != EAGAIN ) + { + Error( "Can't sendto on sd %d: %s", sd, strerror(errno) ); + //exit( -1 ); + } + } - // quit after sending a status, if this was a quit request - if ((MsgCommand)msg->msg_data[0]==CMD_QUIT) + // quit after sending a status, if this was a quit request + if ((MsgCommand)msg->msg_data[0]==CMD_QUIT) exit(0); - updateFrameRate( monitor->GetFPS() ); + updateFrameRate( monitor->GetFPS() ); } bool MonitorStream::sendFrame( const char *filepath, struct timeval *timestamp ) { - bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); + bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); - if ( type != STREAM_JPEG ) - send_raw = false; - if ( !config.timestamp_on_capture && timestamp ) - send_raw = false; + if ( type != STREAM_JPEG ) + send_raw = false; + if ( !config.timestamp_on_capture && timestamp ) + send_raw = false; - if ( !send_raw ) - { - Image temp_image( filepath ); + if ( !send_raw ) + { + Image temp_image( filepath ); - return( sendFrame( &temp_image, timestamp ) ); - } - else - { - int img_buffer_size = 0; - static unsigned char img_buffer[ZM_MAX_IMAGE_SIZE]; + return( sendFrame( &temp_image, timestamp ) ); + } + else + { + int img_buffer_size = 0; + static unsigned char img_buffer[ZM_MAX_IMAGE_SIZE]; - FILE *fdj = NULL; - if ( (fdj = fopen( filepath, "r" )) ) - { - img_buffer_size = fread( img_buffer, 1, sizeof(img_buffer), fdj ); - fclose( fdj ); - } - else - { - Error( "Can't open %s: %s", filepath, strerror(errno) ); - return( false ); - } + FILE *fdj = NULL; + if ( (fdj = fopen( filepath, "r" )) ) + { + img_buffer_size = fread( img_buffer, 1, sizeof(img_buffer), fdj ); + fclose( fdj ); + } + else + { + Error( "Can't open %s: %s", filepath, strerror(errno) ); + return( false ); + } - // Calculate how long it takes to actually send the frame - struct timeval frameStartTime; - gettimeofday( &frameStartTime, NULL ); - - fprintf( stdout, "--ZoneMinderFrame\r\n" ); - fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size ); - fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); - if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) - { - if ( !zm_terminate ) - Error( "Unable to send stream frame: %s", strerror(errno) ); - return( false ); - } - fprintf( stdout, "\r\n\r\n" ); - fflush( stdout ); + // Calculate how long it takes to actually send the frame + struct timeval frameStartTime; + gettimeofday( &frameStartTime, NULL ); + + fprintf( stdout, "--ZoneMinderFrame\r\n" ); + fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size ); + fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); + if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) + { + if ( !zm_terminate ) + Error( "Unable to send stream frame: %s", strerror(errno) ); + return( false ); + } + fprintf( stdout, "\r\n\r\n" ); + fflush( stdout ); - struct timeval frameEndTime; - gettimeofday( &frameEndTime, NULL ); + struct timeval frameEndTime; + gettimeofday( &frameEndTime, NULL ); - int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); - if ( frameSendTime > 1000/maxfps ) - { - maxfps /= 2; - Error( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); - } + int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); + if ( frameSendTime > 1000/maxfps ) + { + maxfps /= 2; + Error( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); + } - last_frame_sent = TV_2_FLOAT( now ); + last_frame_sent = TV_2_FLOAT( now ); - return( true ); - } - return( false ); + return( true ); + } + return( false ); } bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp ) { - Image *send_image = prepareImage( image ); - if ( !config.timestamp_on_capture && timestamp ) - monitor->TimestampImage( send_image, timestamp ); + Image *send_image = prepareImage( image ); + if ( !config.timestamp_on_capture && timestamp ) + monitor->TimestampImage( send_image, timestamp ); #if HAVE_LIBAVCODEC - if ( type == STREAM_MPEG ) - { - if ( !vid_stream ) - { - vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height() ); - fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() ); - vid_stream->OpenStream(); - } - static struct timeval base_time; - struct DeltaTimeval delta_time; - if ( !frame_count ) - base_time = *timestamp; - 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 ); - } - else + if ( type == STREAM_MPEG ) + { + if ( !vid_stream ) + { + vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height() ); + fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() ); + vid_stream->OpenStream(); + } + static struct timeval base_time; + struct DeltaTimeval delta_time; + if ( !frame_count ) + base_time = *timestamp; + 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 ); + } + else #endif // HAVE_LIBAVCODEC - { - static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; + { + static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; - int img_buffer_size = 0; - unsigned char *img_buffer = temp_img_buffer; + int img_buffer_size = 0; + unsigned char *img_buffer = temp_img_buffer; - // Calculate how long it takes to actually send the frame - struct timeval frameStartTime; - gettimeofday( &frameStartTime, NULL ); - - fprintf( stdout, "--ZoneMinderFrame\r\n" ); - switch( type ) - { - case STREAM_JPEG : - send_image->EncodeJpeg( img_buffer, &img_buffer_size ); - fprintf( stdout, "Content-Type: image/jpeg\r\n" ); - break; - case STREAM_RAW : - fprintf( stdout, "Content-Type: image/x-rgb\r\n" ); - img_buffer = (uint8_t*)send_image->Buffer(); - img_buffer_size = send_image->Size(); - break; - case STREAM_ZIP : - fprintf( stdout, "Content-Type: image/x-rgbz\r\n" ); - unsigned long zip_buffer_size; - send_image->Zip( img_buffer, &zip_buffer_size ); - img_buffer_size = zip_buffer_size; - break; - default : - Fatal( "Unexpected frame type %d", type ); - break; - } - fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); - if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) - { - if ( !zm_terminate ) - Error( "Unable to send stream frame: %s", strerror(errno) ); - return( false ); - } - fprintf( stdout, "\r\n\r\n" ); - fflush( stdout ); + // Calculate how long it takes to actually send the frame + struct timeval frameStartTime; + gettimeofday( &frameStartTime, NULL ); + + fprintf( stdout, "--ZoneMinderFrame\r\n" ); + switch( type ) + { + case STREAM_JPEG : + send_image->EncodeJpeg( img_buffer, &img_buffer_size ); + fprintf( stdout, "Content-Type: image/jpeg\r\n" ); + break; + case STREAM_RAW : + fprintf( stdout, "Content-Type: image/x-rgb\r\n" ); + img_buffer = (uint8_t*)send_image->Buffer(); + img_buffer_size = send_image->Size(); + break; + case STREAM_ZIP : + fprintf( stdout, "Content-Type: image/x-rgbz\r\n" ); + unsigned long zip_buffer_size; + send_image->Zip( img_buffer, &zip_buffer_size ); + img_buffer_size = zip_buffer_size; + break; + default : + Fatal( "Unexpected frame type %d", type ); + break; + } + fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); + if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) + { + if ( !zm_terminate ) + Error( "Unable to send stream frame: %s", strerror(errno) ); + return( false ); + } + fprintf( stdout, "\r\n\r\n" ); + fflush( stdout ); - struct timeval frameEndTime; - gettimeofday( &frameEndTime, NULL ); + struct timeval frameEndTime; + gettimeofday( &frameEndTime, NULL ); - int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); - if ( frameSendTime > 1000/maxfps ) - { - maxfps /= 1.5; - Error( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); - } - } - last_frame_sent = TV_2_FLOAT( now ); - return( true ); + int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); + if ( frameSendTime > 1000/maxfps ) + { + maxfps /= 1.5; + Error( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); + } + } + last_frame_sent = TV_2_FLOAT( now ); + return( true ); } void MonitorStream::runStream() { - if ( type == STREAM_SINGLE ) - { - // Not yet migrated over to stream class - monitor->SingleImage( scale ); - return; - } + if ( type == STREAM_SINGLE ) + { + // Not yet migrated over to stream class + monitor->SingleImage( scale ); + return; + } - openComms(); + openComms(); - checkInitialised(); + checkInitialised(); - updateFrameRate( monitor->GetFPS() ); + updateFrameRate( monitor->GetFPS() ); - if ( type == STREAM_JPEG ) - fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); + if ( type == STREAM_JPEG ) + fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); - int last_read_index = monitor->image_buffer_count; + int last_read_index = monitor->image_buffer_count; - time_t stream_start_time; - time( &stream_start_time ); + time_t stream_start_time; + time( &stream_start_time ); - frame_count = 0; + frame_count = 0; - temp_image_buffer = 0; - temp_image_buffer_count = playback_buffer; - temp_read_index = temp_image_buffer_count; - temp_write_index = temp_image_buffer_count; + temp_image_buffer = 0; + temp_image_buffer_count = playback_buffer; + temp_read_index = temp_image_buffer_count; + temp_write_index = temp_image_buffer_count; - char *swap_path = 0; - bool buffered_playback = false; + char *swap_path = 0; + bool buffered_playback = false; - // 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id - const int max_swap_len_suffix = 15; + // 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id + const int max_swap_len_suffix = 15; int swap_path_length = strlen(config.path_swap)+1; // +1 for NULL terminator @@ -4301,318 +4247,318 @@ void MonitorStream::runStream() Debug( 2, "Assigned temporary buffer" ); } } - } + } - float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs) - while ( !zm_terminate ) - { - bool got_command = false; - if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) - { - break; - } + float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs) + while ( !zm_terminate ) + { + bool got_command = false; + if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) + { + break; + } - gettimeofday( &now, NULL ); + gettimeofday( &now, NULL ); - if ( connkey ) - { - while(checkCommandQueue()) { - got_command = true; - } - } + if ( connkey ) + { + while(checkCommandQueue()) { + got_command = true; + } + } - //bool frame_sent = false; - if ( buffered_playback && delayed ) - { - if ( temp_read_index == temp_write_index ) - { - // Go back to live viewing - Debug( 1, "Exceeded temporary streaming buffer" ); - // Clear paused flag - paused = false; - // Clear delayed_play flag - delayed = false; - replay_rate = ZM_RATE_BASE; - } - else - { - if ( !paused ) - { - int temp_index = MOD_ADD( temp_read_index, 0, temp_image_buffer_count ); - //Debug( 3, "tri: %d, ti: %d", temp_read_index, temp_index ); - SwapImage *swap_image = &temp_image_buffer[temp_index]; + //bool frame_sent = false; + if ( buffered_playback && delayed ) + { + if ( temp_read_index == temp_write_index ) + { + // Go back to live viewing + Debug( 1, "Exceeded temporary streaming buffer" ); + // Clear paused flag + paused = false; + // Clear delayed_play flag + delayed = false; + replay_rate = ZM_RATE_BASE; + } + else + { + if ( !paused ) + { + int temp_index = MOD_ADD( temp_read_index, 0, temp_image_buffer_count ); + //Debug( 3, "tri: %d, ti: %d", temp_read_index, temp_index ); + SwapImage *swap_image = &temp_image_buffer[temp_index]; - if ( !swap_image->valid ) - { - paused = true; - delayed = true; - temp_read_index = MOD_ADD( temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count ); - } - else - { - //Debug( 3, "siT: %f, lfT: %f", TV_2_FLOAT( swap_image->timestamp ), TV_2_FLOAT( last_frame_timestamp ) ); - double expected_delta_time = ((TV_2_FLOAT( swap_image->timestamp ) - TV_2_FLOAT( last_frame_timestamp )) * ZM_RATE_BASE)/replay_rate; - double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; + if ( !swap_image->valid ) + { + paused = true; + delayed = true; + temp_read_index = MOD_ADD( temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count ); + } + else + { + //Debug( 3, "siT: %f, lfT: %f", TV_2_FLOAT( swap_image->timestamp ), TV_2_FLOAT( last_frame_timestamp ) ); + double expected_delta_time = ((TV_2_FLOAT( swap_image->timestamp ) - TV_2_FLOAT( last_frame_timestamp )) * ZM_RATE_BASE)/replay_rate; + double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; - //Debug( 3, "eDT: %.3lf, aDT: %.3f, lFS:%.3f, NOW:%.3f", expected_delta_time, actual_delta_time, last_frame_sent, TV_2_FLOAT( now ) ); - // If the next frame is due - if ( actual_delta_time > expected_delta_time ) - { - //Debug( 2, "eDT: %.3lf, aDT: %.3f", expected_delta_time, actual_delta_time ); - if ( temp_index%frame_mod == 0 ) - { - Debug( 2, "Sending delayed frame %d", temp_index ); - // Send the next frame - if ( !sendFrame( temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp ) ) - zm_terminate = true; - memcpy( &last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp) ); - //frame_sent = true; - } - temp_read_index = MOD_ADD( temp_read_index, (replay_rate>0?1:-1), temp_image_buffer_count ); - } - } - } - else if ( step != 0 ) - { - temp_read_index = MOD_ADD( temp_read_index, (step>0?1:-1), temp_image_buffer_count ); + //Debug( 3, "eDT: %.3lf, aDT: %.3f, lFS:%.3f, NOW:%.3f", expected_delta_time, actual_delta_time, last_frame_sent, TV_2_FLOAT( now ) ); + // If the next frame is due + if ( actual_delta_time > expected_delta_time ) + { + //Debug( 2, "eDT: %.3lf, aDT: %.3f", expected_delta_time, actual_delta_time ); + if ( temp_index%frame_mod == 0 ) + { + Debug( 2, "Sending delayed frame %d", temp_index ); + // Send the next frame + if ( !sendFrame( temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp ) ) + zm_terminate = true; + memcpy( &last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp) ); + //frame_sent = true; + } + temp_read_index = MOD_ADD( temp_read_index, (replay_rate>0?1:-1), temp_image_buffer_count ); + } + } + } + else if ( step != 0 ) + { + temp_read_index = MOD_ADD( temp_read_index, (step>0?1:-1), temp_image_buffer_count ); - SwapImage *swap_image = &temp_image_buffer[temp_read_index]; + SwapImage *swap_image = &temp_image_buffer[temp_read_index]; - // Send the next frame - if ( !sendFrame( temp_image_buffer[temp_read_index].file_name, &temp_image_buffer[temp_read_index].timestamp ) ) - zm_terminate = true; - memcpy( &last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp) ); - //frame_sent = true; - step = 0; - } - else - { - int temp_index = MOD_ADD( temp_read_index, 0, temp_image_buffer_count ); + // Send the next frame + if ( !sendFrame( temp_image_buffer[temp_read_index].file_name, &temp_image_buffer[temp_read_index].timestamp ) ) + zm_terminate = true; + memcpy( &last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp) ); + //frame_sent = true; + step = 0; + } + else + { + int temp_index = MOD_ADD( temp_read_index, 0, temp_image_buffer_count ); - double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; - if ( got_command || actual_delta_time > 5 ) - { - // Send keepalive - Debug( 2, "Sending keepalive frame %d", temp_index ); - // Send the next frame - if ( !sendFrame( temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp ) ) - zm_terminate = true; - //frame_sent = true; - } - } - } - if ( temp_read_index == temp_write_index ) - { - // Go back to live viewing - Warning( "Rewound over write index, resuming live play" ); - // Clear paused flag - paused = false; - // Clear delayed_play flag - delayed = false; - replay_rate = ZM_RATE_BASE; - } - } - if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index ) - { - int index = monitor->shared_data->last_write_index%monitor->image_buffer_count; - last_read_index = monitor->shared_data->last_write_index; - //Debug( 1, "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer ); - if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) - { - if ( !paused && !delayed ) - { - // Send the next frame - Monitor::Snapshot *snap = &monitor->image_buffer[index]; + double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; + if ( got_command || actual_delta_time > 5 ) + { + // Send keepalive + Debug( 2, "Sending keepalive frame %d", temp_index ); + // Send the next frame + if ( !sendFrame( temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp ) ) + zm_terminate = true; + //frame_sent = true; + } + } + } + if ( temp_read_index == temp_write_index ) + { + // Go back to live viewing + Warning( "Rewound over write index, resuming live play" ); + // Clear paused flag + paused = false; + // Clear delayed_play flag + delayed = false; + replay_rate = ZM_RATE_BASE; + } + } + if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index ) + { + int index = monitor->shared_data->last_write_index%monitor->image_buffer_count; + last_read_index = monitor->shared_data->last_write_index; + //Debug( 1, "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer ); + if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) + { + if ( !paused && !delayed ) + { + // Send the next frame + Monitor::Snapshot *snap = &monitor->image_buffer[index]; - if ( !sendFrame( snap->image, snap->timestamp ) ) - zm_terminate = true; - memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) ); - //frame_sent = true; + if ( !sendFrame( snap->image, snap->timestamp ) ) + zm_terminate = true; + memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) ); + //frame_sent = true; - temp_read_index = temp_write_index; - } - } - if ( buffered_playback ) - { - if ( monitor->shared_data->valid ) - { - if ( monitor->image_buffer[index].timestamp->tv_sec ) - { - int temp_index = temp_write_index%temp_image_buffer_count; - Debug( 2, "Storing frame %d", temp_index ); - if ( !temp_image_buffer[temp_index].valid ) - { - snprintf( temp_image_buffer[temp_index].file_name, sizeof(temp_image_buffer[0].file_name), "%s/zmswap-i%05d.jpg", swap_path, temp_index ); - temp_image_buffer[temp_index].valid = true; - } - memcpy( &(temp_image_buffer[temp_index].timestamp), monitor->image_buffer[index].timestamp, sizeof(temp_image_buffer[0].timestamp) ); - monitor->image_buffer[index].image->WriteJpeg( temp_image_buffer[temp_index].file_name, config.jpeg_file_quality ); - temp_write_index = MOD_ADD( temp_write_index, 1, temp_image_buffer_count ); - if ( temp_write_index == temp_read_index ) - { - // Go back to live viewing - Warning( "Exceeded temporary buffer, resuming live play" ); - // Clear paused flag - paused = false; - // Clear delayed_play flag - delayed = false; - replay_rate = ZM_RATE_BASE; - } - } - else - { - Warning( "Unable to store frame as timestamp invalid" ); - } - } - else - { - Warning( "Unable to store frame as shared memory invalid" ); - } - } - frame_count++; - } - usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) ); - if ( ttl ) - { - if ( (now.tv_sec - stream_start_time) > ttl ) - { - break; - } - } - if ( (TV_2_FLOAT( now ) - last_frame_sent) > max_secs_since_last_sent_frame ) - { - Error( "Terminating, last frame sent time %f secs more than maximum of %f", TV_2_FLOAT( now ) - last_frame_sent, max_secs_since_last_sent_frame ); - break; - } - } - if ( buffered_playback ) - { - char swap_path[PATH_MAX] = ""; + temp_read_index = temp_write_index; + } + } + if ( buffered_playback ) + { + if ( monitor->shared_data->valid ) + { + if ( monitor->image_buffer[index].timestamp->tv_sec ) + { + int temp_index = temp_write_index%temp_image_buffer_count; + Debug( 2, "Storing frame %d", temp_index ); + if ( !temp_image_buffer[temp_index].valid ) + { + snprintf( temp_image_buffer[temp_index].file_name, sizeof(temp_image_buffer[0].file_name), "%s/zmswap-i%05d.jpg", swap_path, temp_index ); + temp_image_buffer[temp_index].valid = true; + } + memcpy( &(temp_image_buffer[temp_index].timestamp), monitor->image_buffer[index].timestamp, sizeof(temp_image_buffer[0].timestamp) ); + monitor->image_buffer[index].image->WriteJpeg( temp_image_buffer[temp_index].file_name, config.jpeg_file_quality ); + temp_write_index = MOD_ADD( temp_write_index, 1, temp_image_buffer_count ); + if ( temp_write_index == temp_read_index ) + { + // Go back to live viewing + Warning( "Exceeded temporary buffer, resuming live play" ); + // Clear paused flag + paused = false; + // Clear delayed_play flag + delayed = false; + replay_rate = ZM_RATE_BASE; + } + } + else + { + Warning( "Unable to store frame as timestamp invalid" ); + } + } + else + { + Warning( "Unable to store frame as shared memory invalid" ); + } + } + frame_count++; + } + usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) ); + if ( ttl ) + { + if ( (now.tv_sec - stream_start_time) > ttl ) + { + break; + } + } + if ( (TV_2_FLOAT( now ) - last_frame_sent) > max_secs_since_last_sent_frame ) + { + Error( "Terminating, last frame sent time %f secs more than maximum of %f", TV_2_FLOAT( now ) - last_frame_sent, max_secs_since_last_sent_frame ); + break; + } + } + if ( buffered_playback ) + { + char swap_path[PATH_MAX] = ""; - snprintf( swap_path, sizeof(swap_path), "%s/zmswap-m%d/zmswap-q%06d", config.path_swap, monitor->Id(), connkey ); - Debug( 1, "Cleaning swap files from %s", swap_path ); - struct stat stat_buf; - if ( stat( swap_path, &stat_buf ) < 0 ) - { - if ( errno != ENOENT ) - { - Error( "Can't stat '%s': %s", swap_path, strerror(errno) ); - } - } - else if ( !S_ISDIR(stat_buf.st_mode) ) - { - Error( "Swap image path '%s' is not a directory", swap_path ); - } - else - { - char glob_pattern[PATH_MAX] = ""; + snprintf( swap_path, sizeof(swap_path), "%s/zmswap-m%d/zmswap-q%06d", config.path_swap, monitor->Id(), connkey ); + Debug( 1, "Cleaning swap files from %s", swap_path ); + struct stat stat_buf; + if ( stat( swap_path, &stat_buf ) < 0 ) + { + if ( errno != ENOENT ) + { + Error( "Can't stat '%s': %s", swap_path, strerror(errno) ); + } + } + else if ( !S_ISDIR(stat_buf.st_mode) ) + { + Error( "Swap image path '%s' is not a directory", swap_path ); + } + else + { + char glob_pattern[PATH_MAX] = ""; - snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path ); - glob_t pglob; - int glob_status = glob( glob_pattern, 0, 0, &pglob ); - if ( glob_status != 0 ) - { - if ( glob_status < 0 ) - { - Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) ); - } - else - { - Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status ); - } - } - else - { - for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) - { - if ( unlink( pglob.gl_pathv[i] ) < 0 ) - { - Error( "Can't unlink '%s': %s", pglob.gl_pathv[i], strerror(errno) ); - } - } - } - globfree( &pglob ); - if ( rmdir( swap_path ) < 0 ) - { - Error( "Can't rmdir '%s': %s", swap_path, strerror(errno) ); - } - } - } - if ( swap_path ) free( swap_path ); - closeComms(); + snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path ); + glob_t pglob; + int glob_status = glob( glob_pattern, 0, 0, &pglob ); + if ( glob_status != 0 ) + { + if ( glob_status < 0 ) + { + Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) ); + } + else + { + Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status ); + } + } + else + { + for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) + { + if ( unlink( pglob.gl_pathv[i] ) < 0 ) + { + Error( "Can't unlink '%s': %s", pglob.gl_pathv[i], strerror(errno) ); + } + } + } + globfree( &pglob ); + if ( rmdir( swap_path ) < 0 ) + { + Error( "Can't rmdir '%s': %s", swap_path, strerror(errno) ); + } + } + } + if ( swap_path ) free( swap_path ); + closeComms(); } void Monitor::SingleImage( int scale) { - int img_buffer_size = 0; - static JOCTET img_buffer[ZM_MAX_IMAGE_SIZE]; - Image scaled_image; - int index = shared_data->last_write_index%image_buffer_count; - Snapshot *snap = &image_buffer[index]; - Image *snap_image = snap->image; + int img_buffer_size = 0; + static JOCTET img_buffer[ZM_MAX_IMAGE_SIZE]; + Image scaled_image; + int index = shared_data->last_write_index%image_buffer_count; + Snapshot *snap = &image_buffer[index]; + Image *snap_image = snap->image; - if ( scale != ZM_SCALE_BASE ) - { - scaled_image.Assign( *snap_image ); - scaled_image.Scale( scale ); - snap_image = &scaled_image; - } - if ( !config.timestamp_on_capture ) - { - TimestampImage( snap_image, snap->timestamp ); - } - snap_image->EncodeJpeg( img_buffer, &img_buffer_size ); - - fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size ); - fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); - fwrite( img_buffer, img_buffer_size, 1, stdout ); + if ( scale != ZM_SCALE_BASE ) + { + scaled_image.Assign( *snap_image ); + scaled_image.Scale( scale ); + snap_image = &scaled_image; + } + if ( !config.timestamp_on_capture ) + { + TimestampImage( snap_image, snap->timestamp ); + } + snap_image->EncodeJpeg( img_buffer, &img_buffer_size ); + + fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size ); + fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); + fwrite( img_buffer, img_buffer_size, 1, stdout ); } void Monitor::SingleImageRaw( int scale) { - Image scaled_image; - int index = shared_data->last_write_index%image_buffer_count; - Snapshot *snap = &image_buffer[index]; - Image *snap_image = snap->image; + Image scaled_image; + int index = shared_data->last_write_index%image_buffer_count; + Snapshot *snap = &image_buffer[index]; + Image *snap_image = snap->image; - if ( scale != ZM_SCALE_BASE ) - { - scaled_image.Assign( *snap_image ); - scaled_image.Scale( scale ); - snap_image = &scaled_image; - } - if ( !config.timestamp_on_capture ) - { - TimestampImage( snap_image, snap->timestamp ); - } - - fprintf( stdout, "Content-Length: %d\r\n", snap_image->Size() ); - fprintf( stdout, "Content-Type: image/x-rgb\r\n\r\n" ); - fwrite( snap_image->Buffer(), snap_image->Size(), 1, stdout ); + if ( scale != ZM_SCALE_BASE ) + { + scaled_image.Assign( *snap_image ); + scaled_image.Scale( scale ); + snap_image = &scaled_image; + } + if ( !config.timestamp_on_capture ) + { + TimestampImage( snap_image, snap->timestamp ); + } + + fprintf( stdout, "Content-Length: %d\r\n", snap_image->Size() ); + fprintf( stdout, "Content-Type: image/x-rgb\r\n\r\n" ); + fwrite( snap_image->Buffer(), snap_image->Size(), 1, stdout ); } void Monitor::SingleImageZip( int scale) { - unsigned long img_buffer_size = 0; - static Bytef img_buffer[ZM_MAX_IMAGE_SIZE]; - Image scaled_image; - int index = shared_data->last_write_index%image_buffer_count; - Snapshot *snap = &image_buffer[index]; - Image *snap_image = snap->image; + unsigned long img_buffer_size = 0; + static Bytef img_buffer[ZM_MAX_IMAGE_SIZE]; + Image scaled_image; + int index = shared_data->last_write_index%image_buffer_count; + Snapshot *snap = &image_buffer[index]; + Image *snap_image = snap->image; - if ( scale != ZM_SCALE_BASE ) - { - scaled_image.Assign( *snap_image ); - scaled_image.Scale( scale ); - snap_image = &scaled_image; - } - if ( !config.timestamp_on_capture ) - { - TimestampImage( snap_image, snap->timestamp ); - } - snap_image->Zip( img_buffer, &img_buffer_size ); - - fprintf( stdout, "Content-Length: %ld\r\n", img_buffer_size ); - fprintf( stdout, "Content-Type: image/x-rgbz\r\n\r\n" ); - fwrite( img_buffer, img_buffer_size, 1, stdout ); + if ( scale != ZM_SCALE_BASE ) + { + scaled_image.Assign( *snap_image ); + scaled_image.Scale( scale ); + snap_image = &scaled_image; + } + if ( !config.timestamp_on_capture ) + { + TimestampImage( snap_image, snap->timestamp ); + } + snap_image->Zip( img_buffer, &img_buffer_size ); + + fprintf( stdout, "Content-Length: %ld\r\n", img_buffer_size ); + fprintf( stdout, "Content-Type: image/x-rgbz\r\n\r\n" ); + fwrite( img_buffer, img_buffer_size, 1, stdout ); } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 2449561ae..12a43f9ef 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -87,7 +87,7 @@ public: } State; protected: - typedef std::set ZoneSet; + typedef std::set ZoneSet; typedef enum { GET_SETTINGS=0x1, SET_SETTINGS=0x2, RELOAD=0x4, SUSPEND=0x10, RESUME=0x20 } Action; @@ -96,36 +96,36 @@ protected: /* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */ typedef struct { - uint32_t size; /* +0 */ - uint32_t last_write_index; /* +4 */ - uint32_t last_read_index; /* +8 */ - uint32_t state; /* +12 */ - uint32_t last_event; /* +16 */ - uint32_t action; /* +20 */ - int32_t brightness; /* +24 */ - int32_t hue; /* +28 */ - int32_t colour; /* +32 */ - int32_t contrast; /* +36 */ - int32_t alarm_x; /* +40 */ - int32_t alarm_y; /* +44 */ - uint8_t valid; /* +48 */ - uint8_t active; /* +49 */ - uint8_t signal; /* +50 */ - uint8_t format; /* +51 */ - uint32_t imagesize; /* +52 */ - uint32_t epadding1; /* +56 */ - uint32_t epadding2; /* +60 */ + uint32_t size; /* +0 */ + uint32_t last_write_index; /* +4 */ + uint32_t last_read_index; /* +8 */ + uint32_t state; /* +12 */ + uint32_t last_event; /* +16 */ + uint32_t action; /* +20 */ + int32_t brightness; /* +24 */ + int32_t hue; /* +28 */ + int32_t colour; /* +32 */ + int32_t contrast; /* +36 */ + int32_t alarm_x; /* +40 */ + int32_t alarm_y; /* +44 */ + uint8_t valid; /* +48 */ + uint8_t active; /* +49 */ + uint8_t signal; /* +50 */ + uint8_t format; /* +51 */ + uint32_t imagesize; /* +52 */ + uint32_t epadding1; /* +56 */ + uint32_t epadding2; /* +60 */ /* ** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038. ** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16. */ - union { /* +64 */ - time_t last_write_time; - uint64_t extrapad1; + union { /* +64 */ + time_t last_write_time; + uint64_t extrapad1; }; - union { /* +72 */ - time_t last_read_time; - uint64_t extrapad2; + union { /* +72 */ + time_t last_read_time; + uint64_t extrapad2; }; uint8_t control_state[256]; /* +80 */ @@ -134,8 +134,7 @@ protected: typedef enum { TRIGGER_CANCEL, TRIGGER_ON, TRIGGER_OFF } TriggerState; /* sizeof(TriggerData) expected to be 560 on 32bit & and 64bit */ - typedef struct - { + typedef struct { uint32_t size; uint32_t trigger_state; uint32_t trigger_score; @@ -146,29 +145,26 @@ protected: } TriggerData; /* sizeof(Snapshot) expected to be 16 bytes on 32bit and 32 bytes on 64bit */ - struct Snapshot - { + struct Snapshot { struct timeval *timestamp; Image *image; void* padding; }; - //TODO: Technically we can't exclude this struct when people don't have avformat as the Memory.pm module doesn't know about avformat + //TODO: Technically we can't exclude this struct when people don't have avformat as the Memory.pm module doesn't know about avformat #if 1 - //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit - typedef struct - { - uint32_t size; - char event_file[4096]; - uint32_t recording; //bool arch dependent so use uint32 instead - //uint32_t frameNumber; - - } VideoStoreData; - + //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit + typedef struct { + uint32_t size; + char event_file[4096]; + uint32_t recording; //bool arch dependent so use uint32 instead + //uint32_t frameNumber; + + } VideoStoreData; + #endif // HAVE_LIBAVFORMAT - class MonitorLink - { + class MonitorLink { protected: unsigned int id; char name[64]; @@ -178,16 +174,16 @@ protected: #if ZM_MEM_MAPPED int map_fd; - char mem_file[PATH_MAX]; + char mem_file[PATH_MAX]; #else // ZM_MEM_MAPPED - int shm_id; + int shm_id; #endif // ZM_MEM_MAPPED - off_t mem_size; + off_t mem_size; unsigned char *mem_ptr; volatile SharedData *shared_data; volatile TriggerData *trigger_data; - volatile VideoStoreData *video_store_data; + volatile VideoStoreData *video_store_data; int last_state; int last_event; @@ -196,21 +192,17 @@ protected: MonitorLink( int p_id, const char *p_name ); ~MonitorLink(); - inline int Id() const - { + inline int Id() const { return( id ); } - inline const char *Name() const - { + inline const char *Name() const { return( name ); } - inline bool isConnected() const - { + inline bool isConnected() const { return( connected ); } - inline time_t getLastConnectTime() const - { + inline time_t getLastConnectTime() const { return( last_connect_time ); } @@ -227,58 +219,59 @@ protected: unsigned int id; char name[64]; unsigned int server_id; - Function function; // What the monitor is doing - bool enabled; // Whether the monitor is enabled or asleep - unsigned int width; // Normally the same as the camera, but not if partly rotated - unsigned int height; // Normally the same as the camera, but not if partly rotated + Function function; // What the monitor is doing + bool enabled; // Whether the monitor is enabled or asleep + unsigned int width; // Normally the same as the camera, but not if partly rotated + unsigned int height; // Normally the same as the camera, but not if partly rotated bool v4l_multi_buffer; unsigned int v4l_captures_per_frame; - Orientation orientation; // Whether the image has to be rotated at all + Orientation orientation; // Whether the image has to be rotated at all unsigned int deinterlacing; int savejpegspref; int videowriterpref; std::string encoderparams; std::vector encoderparamsvec; + bool record_audio; // Whether to store the audio that we receive - int brightness; // The statically saved brightness of the camera - int contrast; // The statically saved contrast of the camera - int hue; // The statically saved hue of the camera - int colour; // The statically saved colour of the camera - char event_prefix[64]; // The prefix applied to event names as they are created - char label_format[64]; // The format of the timestamp on the images - Coord label_coord; // The coordinates of the timestamp on the images - int label_size; // Size of the timestamp on the images - int image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count - int pre_event_buffer_count; // Size of dedicated circular pre event buffer used when analysis is not performed at capturing framerate, - // value is pre_event_count + alarm_frame_count - 1 - int warmup_count; // How many images to process before looking for events - int pre_event_count; // How many images to hold and prepend to an alarm event - int post_event_count; // How many unalarmed images must occur before the alarm state is reset + int brightness; // The statically saved brightness of the camera + int contrast; // The statically saved contrast of the camera + int hue; // The statically saved hue of the camera + int colour; // The statically saved colour of the camera + char event_prefix[64]; // The prefix applied to event names as they are created + char label_format[64]; // The format of the timestamp on the images + Coord label_coord; // The coordinates of the timestamp on the images + int label_size; // Size of the timestamp on the images + int image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count + int pre_event_buffer_count; // Size of dedicated circular pre event buffer used when analysis is not performed at capturing framerate, + // value is pre_event_count + alarm_frame_count - 1 + int warmup_count; // How many images to process before looking for events + int pre_event_count; // How many images to hold and prepend to an alarm event + int post_event_count; // How many unalarmed images must occur before the alarm state is reset int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now - int section_length; // How long events should last in continuous modes - bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor - int frame_skip; // How many frames to skip in continuous modes - int motion_frame_skip; // How many frames to skip in motion detection - double analysis_fps; // Target framerate for video analysis - unsigned int analysis_update_delay; // How long we wait before updating analysis parameters - int capture_delay; // How long we wait between capture frames - int alarm_capture_delay; // How long we wait between capture frames when in alarm state - int alarm_frame_count; // How many alarm frames are required before an event is triggered - int fps_report_interval; // How many images should be captured/processed between reporting the current FPS - int ref_blend_perc; // Percentage of new image going into reference image. - int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm. - bool track_motion; // Whether this monitor tries to track detected motion - Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected - bool embed_exif; // Whether to embed Exif data into each image frame or not + int section_length; // How long events should last in continuous modes + bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor + int frame_skip; // How many frames to skip in continuous modes + int motion_frame_skip; // How many frames to skip in motion detection + double analysis_fps; // Target framerate for video analysis + unsigned int analysis_update_delay; // How long we wait before updating analysis parameters + int capture_delay; // How long we wait between capture frames + int alarm_capture_delay; // How long we wait between capture frames when in alarm state + int alarm_frame_count; // How many alarm frames are required before an event is triggered + int fps_report_interval; // How many images should be captured/processed between reporting the current FPS + int ref_blend_perc; // Percentage of new image going into reference image. + int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm. + bool track_motion; // Whether this monitor tries to track detected motion + Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected + bool embed_exif; // Whether to embed Exif data into each image frame or not double fps; Image delta_image; Image ref_image; - Image alarm_image; // Used in creating analysis images, will be initialized in Analysis - Image write_image; // Used when creating snapshot images + Image alarm_image; // Used in creating analysis images, will be initialized in Analysis + Image write_image; // Used when creating snapshot images - Purpose purpose; // What this monitor has been created to do + Purpose purpose; // What this monitor has been created to do int event_count; int image_count; int ready_count; @@ -290,22 +283,22 @@ protected: time_t start_time; time_t last_fps_time; time_t auto_resume_time; - unsigned int last_motion_score; + unsigned int last_motion_score; - EventCloseMode event_close_mode; + EventCloseMode event_close_mode; #if ZM_MEM_MAPPED int map_fd; - char mem_file[PATH_MAX]; + char mem_file[PATH_MAX]; #else // ZM_MEM_MAPPED - int shm_id; + int shm_id; #endif // ZM_MEM_MAPPED off_t mem_size; unsigned char *mem_ptr; SharedData *shared_data; TriggerData *trigger_data; - VideoStoreData *video_store_data; + VideoStoreData *video_store_data; Snapshot *image_buffer; Snapshot next_buffer; /* Used by four field deinterlacing */ @@ -329,54 +322,85 @@ protected: public: // OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info. //bool OurCheckAlarms( Zone *zone, const Image *pImage ); - Monitor( int p_id, const char *p_name, unsigned int p_server_id, int p_function, bool p_enabled, const char *p_linked_monitors, Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, int p_savejpegs, int p_videowriter, std::string p_encoderparams, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, int label_size, int p_image_buffer_count, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_stream_replay_buffer, int p_alarm_frame_count, int p_section_length, int p_frame_skip, int p_motion_frame_skip, double p_analysis_fps, unsigned int p_analysis_update_delay, int p_capture_delay, int p_alarm_capture_delay, int p_fps_report_interval, int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, Rgb p_signal_check_colour, bool p_embed_exif, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0 ); + Monitor( + int p_id, + const char *p_name, + unsigned int p_server_id, + int p_function, + bool p_enabled, + const char *p_linked_monitors, + Camera *p_camera, + int p_orientation, + unsigned int p_deinterlacing, + int p_savejpegs, + int p_videowriter, + std::string p_encoderparams, + bool p_record_audio, + const char *p_event_prefix, + const char *p_label_format, + const Coord &p_label_coord, + int label_size, + int p_image_buffer_count, + int p_warmup_count, + int p_pre_event_count, + int p_post_event_count, + int p_stream_replay_buffer, + int p_alarm_frame_count, + int p_section_length, + int p_frame_skip, + int p_motion_frame_skip, + double p_analysis_fps, + unsigned int p_analysis_update_delay, + int p_capture_delay, + int p_alarm_capture_delay, + int p_fps_report_interval, + int p_ref_blend_perc, + int p_alarm_ref_blend_perc, + bool p_track_motion, + Rgb p_signal_check_colour, + bool p_embed_exif, + Purpose p_purpose, + int p_n_zones=0, + Zone *p_zones[]=0 + ); ~Monitor(); void AddZones( int p_n_zones, Zone *p_zones[] ); void AddPrivacyBitmask( Zone *p_zones[] ); bool connect(); - inline int ShmValid() const - { + inline int ShmValid() const { return( shared_data->valid ); } - inline int Id() const - { + inline int Id() const { return( id ); } - inline const char *Name() const - { + inline const char *Name() const { return( name ); } - inline Function GetFunction() const - { + inline Function GetFunction() const { return( function ); } - inline bool Enabled() - { + inline bool Enabled() { if ( function <= MONITOR ) return( false ); return( enabled ); } - inline const char *EventPrefix() const - { + inline const char *EventPrefix() const { return( event_prefix ); } - inline bool Ready() - { + inline bool Ready() { if ( function <= MONITOR ) return( false ); return( image_count > ready_count ); } - inline bool Active() - { + inline bool Active() { if ( function <= MONITOR ) return( false ); return( enabled && shared_data->active ); } - inline bool Exif() - { + inline bool Exif() { return( embed_exif ); } @@ -387,7 +411,7 @@ public: int GetOptSaveJPEGs() const { return( savejpegspref ); } int GetOptVideoWriter() const { return( videowriterpref ); } - const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } + const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } State GetState() const; int GetImage( int index=-1, int scale=100 ); @@ -417,17 +441,14 @@ public: int actionColour( int p_colour=-1 ); int actionContrast( int p_contrast=-1 ); - inline int PrimeCapture() - { + inline int PrimeCapture() { return( camera->PrimeCapture() ); } - inline int PreCapture() - { + inline int PreCapture() { return( camera->PreCapture() ); } int Capture(); - int PostCapture() - { + int PostCapture() { return( camera->PostCapture() ); } @@ -456,7 +477,7 @@ public: static int LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ); #endif // HAVE_LIBAVFORMAT static Monitor *Load( unsigned int id, bool load_zones, Purpose purpose ); - //void writeStreamImage( Image *image, struct timeval *timestamp, int scale, int mag, int x, int y ); + //void writeStreamImage( Image *image, struct timeval *timestamp, int scale, int mag, int x, int y ); //void StreamImages( int scale=100, int maxfps=10, time_t ttl=0, int msq_id=0 ); //void StreamImagesRaw( int scale=100, int maxfps=10, time_t ttl=0 ); //void StreamImagesZip( int scale=100, int maxfps=10, time_t ttl=0 ); @@ -470,53 +491,48 @@ public: #define MOD_ADD( var, delta, limit ) (((var)+(limit)+(delta))%(limit)) -class MonitorStream : public StreamBase -{ +class MonitorStream : public StreamBase { protected: - typedef struct SwapImage { - bool valid; - struct timeval timestamp; - char file_name[PATH_MAX]; - } SwapImage; + typedef struct SwapImage { + bool valid; + struct timeval timestamp; + char file_name[PATH_MAX]; + } SwapImage; private: - SwapImage *temp_image_buffer; - int temp_image_buffer_count; - int temp_read_index; - int temp_write_index; + SwapImage *temp_image_buffer; + int temp_image_buffer_count; + int temp_read_index; + int temp_write_index; protected: - time_t ttl; + time_t ttl; protected: - int playback_buffer; - bool delayed; + int playback_buffer; + bool delayed; - int frame_count; + int frame_count; 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( Image *image, struct timeval *timestamp ); - void processCommand( const CmdMsg *msg ); + bool sendFrame( const char *filepath, struct timeval *timestamp ); + bool sendFrame( Image *image, struct timeval *timestamp ); + void processCommand( const CmdMsg *msg ); public: - MonitorStream() : playback_buffer( 0 ), delayed( false ), frame_count( 0 ) - { - } - void setStreamBuffer( int p_playback_buffer ) - { - playback_buffer = p_playback_buffer; - } - void setStreamTTL( time_t p_ttl ) - { - ttl = p_ttl; - } - bool setStreamStart( int monitor_id ) - { - return loadMonitor( monitor_id ); - } + MonitorStream() : playback_buffer( 0 ), delayed( false ), frame_count( 0 ) { + } + void setStreamBuffer( int p_playback_buffer ) { + playback_buffer = p_playback_buffer; + } + void setStreamTTL( time_t p_ttl ) { + ttl = p_ttl; + } + bool setStreamStart( int monitor_id ) { + return loadMonitor( monitor_id ); + } void runStream(); }; diff --git a/src/zm_remote_camera.cpp b/src/zm_remote_camera.cpp index 8ac4a51ba..388607f6b 100644 --- a/src/zm_remote_camera.cpp +++ b/src/zm_remote_camera.cpp @@ -21,8 +21,23 @@ #include "zm_utils.h" -RemoteCamera::RemoteCamera( int p_id, const std::string &p_protocol, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : - Camera( p_id, REMOTE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ), +RemoteCamera::RemoteCamera( + int p_id, + const std::string &p_protocol, + const std::string &p_host, + const std::string &p_port, + const std::string &p_path, + int p_width, + int p_height, + int p_colours, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio + ) : + Camera( p_id, REMOTE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), protocol( p_protocol ), host( p_host ), port( p_port ), diff --git a/src/zm_remote_camera.h b/src/zm_remote_camera.h index 04823db91..40fc0b523 100644 --- a/src/zm_remote_camera.h +++ b/src/zm_remote_camera.h @@ -55,7 +55,22 @@ protected: struct addrinfo *hp; public: - RemoteCamera( int p_id, const std::string &p_proto, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + RemoteCamera( + int p_id, + const std::string &p_proto, + const std::string &p_host, + const std::string &p_port, + const std::string &p_path, + int p_width, + int p_height, + int p_colours, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio + ); virtual ~RemoteCamera(); const std::string &Protocol() const { return( protocol ); } @@ -73,7 +88,7 @@ public: virtual int PreCapture() = 0; virtual int Capture( Image &image ) = 0; virtual int PostCapture() = 0; - virtual int CaptureAndRecord( Image &image, bool recording, char* event_directory )=0; + virtual int CaptureAndRecord( Image &image, bool recording, char* event_directory )=0; }; #endif // ZM_REMOTE_CAMERA_H diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 006f80faf..4b28048eb 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -31,8 +31,8 @@ #include // FIONREAD and friends #endif -RemoteCameraHttp::RemoteCameraHttp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : - RemoteCamera( p_id, "http", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture ) +RemoteCameraHttp::RemoteCameraHttp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : + RemoteCamera( p_id, "http", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ) { sd = -1; diff --git a/src/zm_remote_camera_http.h b/src/zm_remote_camera_http.h index 15971037e..a5994b9b3 100644 --- a/src/zm_remote_camera_http.h +++ b/src/zm_remote_camera_http.h @@ -45,7 +45,7 @@ protected: enum { SIMPLE, REGEXP } method; public: - RemoteCameraHttp( int p_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + RemoteCameraHttp( int p_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~RemoteCameraHttp(); void Initialise(); @@ -58,7 +58,7 @@ public: int PreCapture(); int Capture( Image &image ); int PostCapture(); - int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; + int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; }; #endif // ZM_REMOTE_CAMERA_HTTP_H diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index a07d97a8e..1d0968ee8 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -28,22 +28,22 @@ #include #include -RemoteCameraRtsp::RemoteCameraRtsp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : - RemoteCamera( p_id, "rtsp", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture ), - rtsp_describe( p_rtsp_describe ), - rtspThread( 0 ) +RemoteCameraRtsp::RemoteCameraRtsp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : + RemoteCamera( p_id, "rtsp", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), + rtsp_describe( p_rtsp_describe ), + rtspThread( 0 ) { - if ( p_method == "rtpUni" ) - method = RtspThread::RTP_UNICAST; - else if ( p_method == "rtpMulti" ) - method = RtspThread::RTP_MULTICAST; - else if ( p_method == "rtpRtsp" ) - method = RtspThread::RTP_RTSP; - else if ( p_method == "rtpRtspHttp" ) - method = RtspThread::RTP_RTSP_HTTP; - else - Fatal( "Unrecognised method '%s' when creating RTSP camera %d", p_method.c_str(), id ); + if ( p_method == "rtpUni" ) + method = RtspThread::RTP_UNICAST; + else if ( p_method == "rtpMulti" ) + method = RtspThread::RTP_MULTICAST; + else if ( p_method == "rtpRtsp" ) + method = RtspThread::RTP_RTSP; + else if ( p_method == "rtpRtspHttp" ) + method = RtspThread::RTP_RTSP_HTTP; + else + Fatal( "Unrecognised method '%s' when creating RTSP camera %d", p_method.c_str(), id ); if ( capture ) { @@ -52,13 +52,16 @@ RemoteCameraRtsp::RemoteCameraRtsp( int p_id, const std::string &p_method, const mFormatContext = NULL; mVideoStreamId = -1; + mAudioStreamId = -1; mCodecContext = NULL; mCodec = NULL; mRawFrame = NULL; mFrame = NULL; frameCount = 0; + wasRecording = false; + startTime=0; -#if HAVE_LIBSWSCALE +#if HAVE_LIBSWSCALE mConvertContext = NULL; #endif /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ @@ -80,26 +83,26 @@ RemoteCameraRtsp::RemoteCameraRtsp( int p_id, const std::string &p_method, const RemoteCameraRtsp::~RemoteCameraRtsp() { #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - av_frame_free( &mFrame ); - av_frame_free( &mRawFrame ); + av_frame_free( &mFrame ); + av_frame_free( &mRawFrame ); #else - av_freep( &mFrame ); - av_freep( &mRawFrame ); + av_freep( &mFrame ); + av_freep( &mRawFrame ); #endif - + #if HAVE_LIBSWSCALE - if ( mConvertContext ) - { - sws_freeContext( mConvertContext ); - mConvertContext = NULL; - } + if ( mConvertContext ) + { + sws_freeContext( mConvertContext ); + mConvertContext = NULL; + } #endif - if ( mCodecContext ) - { - avcodec_close( mCodecContext ); - mCodecContext = NULL; // Freed by avformat_free_context in the destructor of RtspThread class - } + if ( mCodecContext ) + { + avcodec_close( mCodecContext ); + mCodecContext = NULL; // Freed by avformat_free_context in the destructor of RtspThread class + } if ( capture ) { @@ -109,106 +112,109 @@ RemoteCameraRtsp::~RemoteCameraRtsp() void RemoteCameraRtsp::Initialise() { - RemoteCamera::Initialise(); + RemoteCamera::Initialise(); int max_size = width*height*colours; + // This allocates a buffer able to hold a raw fframe, which is a little artbitrary. Might be nice to get some + // decent data on how large a buffer is really needed. buffer.size( max_size ); - if ( logDebugging() ) - av_log_set_level( AV_LOG_DEBUG ); - else - av_log_set_level( AV_LOG_QUIET ); + if ( logDebugging() ) + av_log_set_level( AV_LOG_DEBUG ); + else + av_log_set_level( AV_LOG_QUIET ); - av_register_all(); + av_register_all(); - Connect(); + Connect(); } void RemoteCameraRtsp::Terminate() { - Disconnect(); + Disconnect(); } int RemoteCameraRtsp::Connect() { - rtspThread = new RtspThread( id, method, protocol, host, port, path, auth, rtsp_describe ); + rtspThread = new RtspThread( id, method, protocol, host, port, path, auth, rtsp_describe ); - rtspThread->start(); + rtspThread->start(); - return( 0 ); + return( 0 ); } int RemoteCameraRtsp::Disconnect() { - if ( rtspThread ) - { - rtspThread->stop(); - rtspThread->join(); - delete rtspThread; - rtspThread = 0; - } - return( 0 ); + if ( rtspThread ) + { + rtspThread->stop(); + rtspThread->join(); + delete rtspThread; + rtspThread = 0; + } + return( 0 ); } int RemoteCameraRtsp::PrimeCapture() { - Debug( 2, "Waiting for sources" ); - for ( int i = 0; i < 100 && !rtspThread->hasSources(); i++ ) - { - usleep( 100000 ); - } - if ( !rtspThread->hasSources() ) - Fatal( "No RTSP sources" ); + Debug( 2, "Waiting for sources" ); + for ( int i = 0; i < 100 && !rtspThread->hasSources(); i++ ) + { + usleep( 100000 ); + } + if ( !rtspThread->hasSources() ) + Fatal( "No RTSP sources" ); - Debug( 2, "Got sources" ); + Debug( 2, "Got sources" ); - mFormatContext = rtspThread->getFormatContext(); + mFormatContext = rtspThread->getFormatContext(); - // Find first video stream present - mVideoStreamId = -1; - - for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) + // Find first video stream present + mVideoStreamId = -1; + + // Find the first video stream. + for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) #endif - { - mVideoStreamId = i; - break; - } - if ( mVideoStreamId == -1 ) - Fatal( "Unable to locate video stream" ); + { + mVideoStreamId = i; + break; + } + if ( mVideoStreamId == -1 ) + Fatal( "Unable to locate video stream" ); - // Get a pointer to the codec context for the video stream - mCodecContext = mFormatContext->streams[mVideoStreamId]->codec; + // Get a pointer to the codec context for the video stream + mCodecContext = mFormatContext->streams[mVideoStreamId]->codec; - // Find the decoder for the video stream - mCodec = avcodec_find_decoder( mCodecContext->codec_id ); - if ( mCodec == NULL ) - Panic( "Unable to locate codec %d decoder", mCodecContext->codec_id ); + // Find the decoder for the video stream + mCodec = avcodec_find_decoder( mCodecContext->codec_id ); + if ( mCodec == NULL ) + Panic( "Unable to locate codec %d decoder", mCodecContext->codec_id ); - // Open codec + // Open codec #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) - if ( avcodec_open( mCodecContext, mCodec ) < 0 ) + if ( avcodec_open( mCodecContext, mCodec ) < 0 ) #else - if ( avcodec_open2( mCodecContext, mCodec, 0 ) < 0 ) + if ( avcodec_open2( mCodecContext, mCodec, 0 ) < 0 ) #endif - Panic( "Can't open codec" ); + Panic( "Can't open codec" ); - // Allocate space for the native video frame + // Allocate space for the native video frame #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - mRawFrame = av_frame_alloc(); + mRawFrame = av_frame_alloc(); #else - mRawFrame = avcodec_alloc_frame(); + mRawFrame = avcodec_alloc_frame(); #endif - // Allocate space for the converted video frame + // Allocate space for the converted video frame #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - mFrame = av_frame_alloc(); + mFrame = av_frame_alloc(); #else - mFrame = avcodec_alloc_frame(); + mFrame = avcodec_alloc_frame(); #endif if(mRawFrame == NULL || mFrame == NULL) @@ -229,27 +235,25 @@ int RemoteCameraRtsp::PrimeCapture() } #else // HAVE_LIBSWSCALE - Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); + Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); #endif // HAVE_LIBSWSCALE */ - return( 0 ); + return( 0 ); } -int RemoteCameraRtsp::PreCapture() -{ - if ( !rtspThread->isRunning() ) - return( -1 ); - if ( !rtspThread->hasSources() ) - { - Error( "Cannot precapture, no RTP sources" ); - return( -1 ); - } - return( 0 ); +int RemoteCameraRtsp::PreCapture() { + if ( !rtspThread->isRunning() ) + return( -1 ); + if ( !rtspThread->hasSources() ) + { + Error( "Cannot precapture, no RTP sources" ); + return( -1 ); + } + return( 0 ); } -int RemoteCameraRtsp::Capture( Image &image ) -{ +int RemoteCameraRtsp::Capture( Image &image ) { AVPacket packet; uint8_t* directbuffer; int frameComplete = false; @@ -261,111 +265,279 @@ int RemoteCameraRtsp::Capture( Image &image ) return (-1); } - while ( true ) - { - buffer.clear(); - if ( !rtspThread->isRunning() ) - return (-1); + while ( true ) { + buffer.clear(); + if ( !rtspThread->isRunning() ) + return (-1); - if ( rtspThread->getFrame( buffer ) ) - { - Debug( 3, "Read frame %d bytes", buffer.size() ); - Debug( 4, "Address %p", buffer.head() ); - Hexdump( 4, buffer.head(), 16 ); + if ( rtspThread->getFrame( buffer ) ) { + Debug( 3, "Read frame %d bytes", buffer.size() ); + Debug( 4, "Address %p", buffer.head() ); + Hexdump( 4, buffer.head(), 16 ); - if ( !buffer.size() ) - return( -1 ); + if ( !buffer.size() ) + return( -1 ); - if(mCodecContext->codec_id == AV_CODEC_ID_H264) - { - // SPS and PPS frames should be saved and appended to IDR frames - int nalType = (buffer.head()[3] & 0x1f); - - // SPS - if(nalType == 7) - { - lastSps = buffer; - continue; - } - // PPS - else if(nalType == 8) - { - lastPps = buffer; - continue; - } - // IDR - else if(nalType == 5) - { - buffer += lastSps; - buffer += lastPps; - } - } + if(mCodecContext->codec_id == AV_CODEC_ID_H264) { + // SPS and PPS frames should be saved and appended to IDR frames + int nalType = (buffer.head()[3] & 0x1f); + + // SPS The SPS NAL unit contains parameters that apply to a series of consecutive coded video pictures + if(nalType == 7) + { + lastSps = buffer; + continue; + } + // PPS The PPS NAL unit contains parameters that apply to the decoding of one or more individual pictures inside a coded video sequence + else if(nalType == 8) + { + lastPps = buffer; + continue; + } + // IDR + else if(nalType == 5) + { + buffer += lastSps; + buffer += lastPps; + } + } - av_init_packet( &packet ); - - while ( !frameComplete && buffer.size() > 0 ) - { - packet.data = buffer.head(); - packet.size = buffer.size(); -#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) - int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ); -#else - int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ); -#endif - if ( len < 0 ) - { - Error( "Error while decoding frame %d", frameCount ); - Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() ); - buffer.clear(); - continue; - } - Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() ); - //if ( buffer.size() < 400 ) - //Hexdump( 0, buffer.head(), buffer.size() ); - - buffer -= len; - - } - if ( frameComplete ) { - - Debug( 3, "Got frame %d", frameCount ); - - avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); + av_init_packet( &packet ); -#if HAVE_LIBSWSCALE - if(mConvertContext == NULL) { - mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); + while ( !frameComplete && buffer.size() > 0 ) { + packet.data = buffer.head(); + packet.size = buffer.size(); - if(mConvertContext == NULL) - Fatal( "Unable to create conversion context"); - } - - if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 ) - Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount ); -#else // HAVE_LIBSWSCALE - Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); -#endif // HAVE_LIBSWSCALE - - frameCount++; + // So I think this is the magic decode step. Result is a raw image? + #if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) + int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ); + #else + int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ); + #endif + if ( len < 0 ) { + Error( "Error while decoding frame %d", frameCount ); + Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() ); + buffer.clear(); + continue; + } + Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() ); + //if ( buffer.size() < 400 ) + //Hexdump( 0, buffer.head(), buffer.size() ); + + buffer -= len; + } + // At this point, we either have a frame or ran out of buffer. What happens if we run out of buffer? + if ( frameComplete ) { + + Debug( 3, "Got frame %d", frameCount ); + + avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height ); + + #if HAVE_LIBSWSCALE + if(mConvertContext == NULL) { + mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); - } /* frame complete */ - -#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100) - av_packet_unref( &packet); -#else - av_free_packet( &packet ); -#endif - } /* getFrame() */ - - if(frameComplete) - return (0); + if(mConvertContext == NULL) + Fatal( "Unable to create conversion context"); + } + + if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 ) + Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount ); + #else // HAVE_LIBSWSCALE + Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); + #endif // HAVE_LIBSWSCALE + + frameCount++; + + } /* frame complete */ + + #if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100) + av_packet_unref( &packet ); + #else + av_free_packet( &packet ); + #endif + } /* getFrame() */ + + if(frameComplete) + return (0); - } - return (0) ; + } // end while true + + // can never get here. + return (0) ; } +//Function to handle capture and store +int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* event_file ) { + AVPacket packet; + uint8_t* directbuffer; + int frameComplete = false; + + /* Request a writeable buffer of the target image */ + directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); + if(directbuffer == NULL) { + Error("Failed requesting writeable buffer for the captured image."); + return (-1); + } + + while ( true ) { + buffer.clear(); + if ( !rtspThread->isRunning() ) + return (-1); + + if ( rtspThread->getFrame( buffer ) ) { + Debug( 3, "Read frame %d bytes", buffer.size() ); + Debug( 4, "Address %p", buffer.head() ); + Hexdump( 4, buffer.head(), 16 ); + + if ( !buffer.size() ) + return( -1 ); + + if(mCodecContext->codec_id == AV_CODEC_ID_H264) { + // SPS and PPS frames should be saved and appended to IDR frames + int nalType = (buffer.head()[3] & 0x1f); + + // SPS + if(nalType == 7) { + lastSps = buffer; + continue; + } + // PPS + else if(nalType == 8) { + lastPps = buffer; + continue; + } + // IDR + else if(nalType == 5) { + buffer += lastSps; + buffer += lastPps; + } + } // end if H264, what about other codecs? + + av_init_packet( &packet ); + + // Why are we checking for it being the video stream + if ( packet.stream_index == mVideoStreamId ) { + + while ( !frameComplete && buffer.size() > 0 ) { + packet.data = buffer.head(); + packet.size = buffer.size(); + + // So this does the decode +#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) + int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ); +#else + int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ); +#endif + if ( len < 0 ) { + Error( "Error while decoding frame %d", frameCount ); + Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() ); + buffer.clear(); + continue; + } + Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() ); + //if ( buffer.size() < 400 ) + //Hexdump( 0, buffer.head(), buffer.size() ); + + buffer -= len; + } // end while get & decode a frame + + if ( frameComplete ) { + + Debug( 3, "Got frame %d", frameCount ); + + avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height ); + + //Video recording + if ( recording && !wasRecording ) { + //Instantiate the video storage module + + videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime); + wasRecording = true; + strcpy(oldDirectory, event_file); + + } else if ( !recording && wasRecording && videoStore ) { + // Why are we deleting the videostore? Becase for soem reason we are no longer recording? How does that happen? + Info("Deleting videoStore instance"); + delete videoStore; + videoStore = NULL; + } + + //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 + if ( recording && wasRecording && (strcmp(oldDirectory, event_file)!=0) && (packet.flags & AV_PKT_FLAG_KEY) ) { + //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"); + if ( videoStore ) { + delete videoStore; + videoStore = NULL; + } + + videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime); + strcpy( oldDirectory, event_file ); + } + + if ( videoStore && recording ) { + //Write the packet to our video store + int ret = videoStore->writeVideoFramePacket(&packet, mFormatContext->streams[mVideoStreamId]);//, &lastKeyframePkt); + if ( ret < 0 ) {//Less than zero and we skipped a frame + av_free_packet( &packet ); + return 0; + } + } + +#if HAVE_LIBSWSCALE + if(mConvertContext == NULL) { + mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); + + if(mConvertContext == NULL) + Fatal( "Unable to create conversion context"); + } + + if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 ) + Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount ); +#else // HAVE_LIBSWSCALE + Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); +#endif // HAVE_LIBSWSCALE + + frameCount++; + + } /* frame complete */ + } else if ( packet.stream_index == mAudioStreamId ) { + Debug( 4, "Got audio packet" ); + if ( videoStore && recording ) { + if ( 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 + if ( ret < 0 ) { //Less than zero and we skipped a frame +#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100) + av_packet_unref( &packet ); +#else + av_free_packet( &packet ); +#endif + return 0; + } + } else { + Debug( 4, "Not storing audio" ); + } + } + } // end if video or audio packet + +#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100) + av_packet_unref( &packet ); +#else + av_free_packet( &packet ); +#endif + } /* getFrame() */ + + if(frameComplete) + return (0); + } // end while true + return (0) ; +} // int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* event_file ) + int RemoteCameraRtsp::PostCapture() { - return( 0 ); + return( 0 ); } #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_remote_camera_rtsp.h b/src/zm_remote_camera_rtsp.h index 1e2bba7f8..6de7fddc1 100644 --- a/src/zm_remote_camera_rtsp.h +++ b/src/zm_remote_camera_rtsp.h @@ -26,6 +26,7 @@ #include "zm_utils.h" #include "zm_rtsp.h" #include "zm_ffmpeg.h" +#include "zm_videostore.h" // // Class representing 'rtsp' cameras, i.e. those which are @@ -40,11 +41,11 @@ protected: int rtsp_sd; int rtp_sd; int rtcp_sd; - bool rtsp_describe; + bool rtsp_describe; Buffer buffer; - Buffer lastSps; - Buffer lastPps; + Buffer lastSps; + Buffer lastPps; RtspThread::RtspMethod method; @@ -55,31 +56,36 @@ protected: #if HAVE_LIBAVFORMAT AVFormatContext *mFormatContext; int mVideoStreamId; + int mAudioStreamId; AVCodecContext *mCodecContext; AVCodec *mCodec; AVFrame *mRawFrame; AVFrame *mFrame; _AVPIXELFORMAT imagePixFormat; #endif // HAVE_LIBAVFORMAT + bool wasRecording; + VideoStore *videoStore; + char oldDirectory[4096]; + int64_t startTime; #if HAVE_LIBSWSCALE struct SwsContext *mConvertContext; #endif public: - RemoteCameraRtsp( int p_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + RemoteCameraRtsp( int p_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~RemoteCameraRtsp(); void Initialise(); void Terminate(); - int Connect(); - int Disconnect(); + int Connect(); + int Disconnect(); int PrimeCapture(); int PreCapture(); int Capture( Image &image ); int PostCapture(); - int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; + int CaptureAndRecord( Image &image, bool recording, char* event_directory ); }; #endif // ZM_REMOTE_CAMERA_RTSP_H diff --git a/src/zm_rtp_source.cpp b/src/zm_rtp_source.cpp index a61bfffe3..a4dfcd5d7 100644 --- a/src/zm_rtp_source.cpp +++ b/src/zm_rtp_source.cpp @@ -262,6 +262,11 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) int rtpHeaderSize = 12 + rtpHeader->cc * 4; // No need to check for nal type as non fragmented packets already have 001 start sequence appended bool h264FragmentEnd = (mCodecId == AV_CODEC_ID_H264) && (packet[rtpHeaderSize+1] & 0x40); + // M stands for Market, it is the 8th bit + // The interpretation of the marker is defined by a profile. It is intended + // to allow significant events such as frame boundaries to be marked in the + // packet stream. A profile may define additional marker bits or specify + // that there is no marker bit by changing the number of bits in the payload type field. bool thisM = rtpHeader->m || h264FragmentEnd; if ( updateSeq( ntohs(rtpHeader->seqN) ) ) @@ -275,15 +280,18 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) if( mCodecId == AV_CODEC_ID_H264 ) { int nalType = (packet[rtpHeaderSize] & 0x1f); + Debug( 3, "Have H264 frame: nal type is %d", nalType ); switch (nalType) { - case 24: + case 24: // STAP-A { extraHeader = 2; break; } - case 25: case 26: case 27: + case 25: // STAP-B + case 26: // MTAP-16 + case 27: // MTAP-24 { extraHeader = 3; break; @@ -304,6 +312,9 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) extraHeader = 2; break; } + default: { + Debug(3, "Unhandled nalType %d", nalType ); + } } // Append NAL frame start code @@ -311,6 +322,8 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) mFrame.append( "\x0\x0\x1", 3 ); } mFrame.append( packet+rtpHeaderSize+extraHeader, packetLen-rtpHeaderSize-extraHeader ); + } else { + Debug( 3, "NOT H264 frame: type is %d", mCodecId ); } Hexdump( 4, mFrame.head(), 16 ); diff --git a/src/zm_video.cpp b/src/zm_video.cpp index 82cb75d1d..65e4a32e8 100644 --- a/src/zm_video.cpp +++ b/src/zm_video.cpp @@ -64,7 +64,7 @@ X264MP4Writer::X264MP4Writer(const char* p_path, const unsigned int p_width, con if(zm_pf == 0) { Error("Unable to match ffmpeg pixelformat"); } - codec_pf = AV_PIX_FMT_YUV420P; + codec_pf = PIX_FMT_YUV420P; swscaleobj.SetDefaults(zm_pf, codec_pf, width, height); diff --git a/src/zm_video.h b/src/zm_video.h index 936adfeb8..45fe0f078 100644 --- a/src/zm_video.h +++ b/src/zm_video.h @@ -120,8 +120,8 @@ protected: /* SWScale */ SWScale swscaleobj; - enum _AVPIXELFORMAT zm_pf; - enum _AVPIXELFORMAT codec_pf; + enum PixelFormat zm_pf; + enum PixelFormat codec_pf; size_t codec_imgsize; size_t zm_imgsize; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp old mode 100755 new mode 100644 diff --git a/src/zm_videostore.h b/src/zm_videostore.h old mode 100755 new mode 100644 diff --git a/version b/version index 5e57fb895..034552a83 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.29.0 +1.30.0 diff --git a/web/api/.gitattributes b/web/api/.gitattributes deleted file mode 100644 index fc3f49166..000000000 --- a/web/api/.gitattributes +++ /dev/null @@ -1,33 +0,0 @@ -# Define the line ending behavior of the different file extensions -# Set default behaviour, in case users don't have core.autocrlf set. -* text=auto - -# Explicitly declare text files we want to always be normalized and converted -# to native line endings on checkout. -*.php text -*.default text -*.ctp text -*.sql text -*.md text -*.po text -*.js text -*.css text -*.ini text -*.properties text -*.txt text -*.xml text -*.yml text -.htaccess text - -# Declare files that will always have CRLF line endings on checkout. -*.bat eol=crlf - -# Declare files that will always have LF line endings on checkout. -*.pem eol=lf - -# Denote all files that are truly binary and should not be modified. -*.png binary -*.jpg binary -*.gif binary -*.ico binary -*.mo binary \ No newline at end of file diff --git a/web/api/.gitignore b/web/api/.gitignore deleted file mode 100644 index 4a1adb886..000000000 --- a/web/api/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# User specific & automatically generated files # -################################################# -/app/Config/database.php -/app/tmp -/lib/Cake/Console/Templates/skel/tmp/ -/plugins -/vendors -/build -/dist -/tags - -# OS generated files # -###################### -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -Icon? -ehthumbs.db -Thumbs.db \ No newline at end of file diff --git a/web/includes/functions.php b/web/includes/functions.php index 5b5b0972f..d3a340640 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1153,30 +1153,38 @@ function zmaCheck( $monitor ) function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false ) { - $eventPath = getEventPath( $event ); + $eventPath = ZM_DIR_EVENTS.'/'.getEventPath( $event ); if ( !is_array($frame) ) $frame = array( 'FrameId'=>$frame, 'Type'=>'' ); - //echo "S:$scale, CO:$captureOnly
"; - $currEvent = dbFetchOne( 'SELECT M.SaveJPEGs FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = '.$event['Id'] ); - if ( $currEvent['SaveJPEGs'] == "4" ) + if ( file_exists( $eventPath.'/snapshot.jpg' ) ) { $captImage = "snapshot.jpg"; - else + } else { $captImage = sprintf( "%0".ZM_EVENT_IMAGE_DIGITS."d-capture.jpg", $frame['FrameId'] ); + if ( ! file_exists( $eventPath.'/'.$captImage ) ) { + # Generate the frame JPG + if ( $event['DefaultVideo'] ) { + $command ='ffmpeg -v 0 -i '.$eventPath.'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage; + system( $command, $output, $retval ); + } else { + Error("Can't create frame images from video becuase there is no video file for this event " ); + } + } + } + $captPath = $eventPath.'/'.$captImage; $thumbCaptPath = ZM_DIR_IMAGES.'/'.$event['Id'].'-'.$captImage; //echo "CI:$captImage, CP:$captPath, TCP:$thumbCaptPath
"; $analImage = sprintf( "%0".ZM_EVENT_IMAGE_DIGITS."d-analyse.jpg", $frame['FrameId'] ); $analPath = $eventPath.'/'.$analImage; - $analFile = ZM_DIR_EVENTS."/".$analPath; $thumbAnalPath = ZM_DIR_IMAGES.'/'.$event['Id'].'-'.$analImage; //echo "AI:$analImage, AP:$analPath, TAP:$thumbAnalPath
"; $alarmFrame = $frame['Type']=='Alarm'; - $hasAnalImage = $alarmFrame && file_exists( $analFile ) && filesize( $analFile ); + $hasAnalImage = $alarmFrame && file_exists( $analPath ) && filesize( $analPath ); $isAnalImage = $hasAnalImage && !$captureOnly; if ( !ZM_WEB_SCALE_THUMBS || $scale >= SCALE_BASE || !function_exists( 'imagecreatefromjpeg' ) ) @@ -1207,22 +1215,20 @@ function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $ov $thumbPath = $thumbCaptPath; } - $imageFile = ZM_DIR_EVENTS."/".$imagePath; - //$thumbFile = ZM_DIR_EVENTS."/".$thumbPath; $thumbFile = $thumbPath; if ( $overwrite || !file_exists( $thumbFile ) || !filesize( $thumbFile ) ) { // Get new dimensions - list( $imageWidth, $imageHeight ) = getimagesize( $imageFile ); + list( $imageWidth, $imageHeight ) = getimagesize( $imagePath ); $thumbWidth = $imageWidth * $fraction; $thumbHeight = $imageHeight * $fraction; // Resample $thumbImage = imagecreatetruecolor( $thumbWidth, $thumbHeight ); - $image = imagecreatefromjpeg( $imageFile ); + $image = imagecreatefromjpeg( $imagePath ); imagecopyresampled( $thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight ); - if ( !imagejpeg( $thumbImage, $thumbFile ) ) + if ( !imagejpeg( $thumbImage, $thumbPath ) ) Error( "Can't create thumbnail '$thumbPath'" ); } } @@ -1231,15 +1237,13 @@ function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $ov 'eventPath' => $eventPath, 'imagePath' => $imagePath, 'thumbPath' => $thumbPath, - 'imageFile' => $imageFile, + 'imageFile' => $imagePath, 'thumbFile' => $thumbFile, 'imageClass' => $alarmFrame?"alarm":"normal", 'isAnalImage' => $isAnalImage, 'hasAnalImage' => $hasAnalImage, ); - //echo "IP:$imagePath
"; - //echo "TP:$thumbPath
"; return( $imageData ); } diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 7b5e07527..bf58c48dc 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -584,6 +584,7 @@ $SLANG = array( 'Protocol' => 'Protocol', 'Rate' => 'Rate', 'RecaptchaWarning' => 'Your reCaptcha secret key is invalid. Please correct it, or reCaptcha will not work', // added Sep 24 2015 - PP + 'RecordAudio' => 'Whether to store the audio stream when saving an event.', 'Real' => 'Real', 'Record' => 'Record', 'RefImageBlendPct' => 'Reference Image Blend %ge', diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 8b146cc7d..97fd71130 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -55,7 +55,7 @@ $replayModes = array( if ( isset( $_REQUEST['streamMode'] ) ) $streamMode = validHtmlStr($_REQUEST['streamMode']); else - $streamMode = video; + $streamMode = 'video'; if ( isset( $_REQUEST['replayMode'] ) ) $replayMode = validHtmlStr($_REQUEST['replayMode']); diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 68e595e4a..59a002c0e 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -86,6 +86,7 @@ if ( ! empty($_REQUEST['mid']) ) { 'SaveJPEGs' => "3", 'VideoWriter' => "0", 'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", + 'RecordAudio' => "0", 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S', 'LabelX' => 0, 'LabelY' => 0, @@ -593,6 +594,7 @@ if ( $tab != 'storage' ) + + checked="checked"/>