diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 4d96f11db7..495e53d296 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -3945,7 +3945,15 @@ our @options = ( help => q`This will affect how long a session will be valid for since the last request. Keeping this short helps prevent session hijacking. Keeping it long allows you to stay logged in longer without refreshing the view.`, type => $types{integer}, category => 'system', - } + }, + { + name => 'ZM_RECORD_DIAG_IMAGES_FIFO', + default => 'no', + description => ' Recording intermediate alarm diagnostic use fifo instead of files (faster)', + help => 'This tries to lessen the load of recording diag images by sending them to a memory FIFO pipe instead of creating each file.', + type => $types{boolean}, + category => 'logging', + }, ); our %options_hash = map { ( $_->{name}, $_ ) } @options; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e7e3157eba..e27c36d6ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY) # Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc) -set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_frame.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_input.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp) +set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_frame.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_input.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_fifo.cpp zm_storage.cpp) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp new file mode 100644 index 0000000000..538b696fae --- /dev/null +++ b/src/zm_fifo.cpp @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include +#include + +#include "zm.h" +#include "zm_db.h" +#include "zm_time.h" +#include "zm_mpeg.h" +#include "zm_signal.h" +#include "zm_monitor.h" +#include "zm_fifo.h" +#define RAW_BUFFER 512 +static bool zm_fifodbg_inited = false; +FILE *zm_fifodbg_log_fd = 0; +char zm_fifodbg_log[PATH_MAX] = ""; + +static bool zmFifoDbgOpen(){ + if (zm_fifodbg_log_fd) + fclose(zm_fifodbg_log_fd); + zm_fifodbg_log_fd = NULL; + signal(SIGPIPE, SIG_IGN); + FifoStream::fifo_create_if_missing(zm_fifodbg_log); + int fd = open(zm_fifodbg_log,O_WRONLY|O_NONBLOCK|O_TRUNC); + if (fd < 0) + return ( false ); + int res = flock(fd,LOCK_EX | LOCK_NB); + if (res < 0) + { + close(fd); + return ( false ); + } + zm_fifodbg_log_fd = fdopen(fd,"wb"); + if (zm_fifodbg_log_fd == NULL) + { + close(fd); + return ( false ); + } + return ( true ); +} +int zmFifoDbgInit(Monitor *monitor){ + zm_fifodbg_inited = true; + snprintf( zm_fifodbg_log, sizeof(zm_fifodbg_log), "%s/%d/dbgpipe.log", monitor->getStorage()->Path(), monitor->Id() ); + zmFifoDbgOpen(); + return 1; +} +void zmFifoDbgOutput( int hex, const char * const file, const int line, const int level, const char *fstring, ... ){ + char dbg_string[8192]; + va_list arg_ptr; + if (! zm_fifodbg_inited) + return; + if (! zm_fifodbg_log_fd && ! zmFifoDbgOpen()) + return; + + char *dbg_ptr = dbg_string; + va_start( arg_ptr, fstring ); + if ( hex ) + { + unsigned char *data = va_arg( arg_ptr, unsigned char * ); + int len = va_arg( arg_ptr, int ); + int i; + dbg_ptr += snprintf( dbg_ptr, sizeof(dbg_string)-(dbg_ptr-dbg_string), "%d:", len ); + for ( i = 0; i < len; i++ ) + { + dbg_ptr += snprintf( dbg_ptr, sizeof(dbg_string)-(dbg_ptr-dbg_string), " %02x", data[i] ); + } + } + else + { + dbg_ptr += vsnprintf( dbg_ptr, sizeof(dbg_string)-(dbg_ptr-dbg_string), fstring, arg_ptr ); + } + va_end(arg_ptr); + strncpy( dbg_ptr++, "\n", 1); + int res = fwrite( dbg_string, dbg_ptr-dbg_string, 1, zm_fifodbg_log_fd ); + if (res != 1){ + fclose(zm_fifodbg_log_fd); + zm_fifodbg_log_fd = NULL; + } + else + { + fflush(zm_fifodbg_log_fd); + } +} +bool FifoStream::sendRAWFrames(){ + static unsigned char buffer[RAW_BUFFER]; + int fd = open(stream_path,O_RDONLY); + if (fd < 0) + { + Error( "Can't open %s: %s", stream_path, strerror(errno)); + return( false ); + } + while( (bytes_read = read(fd,buffer,RAW_BUFFER)) ) + { + if (bytes_read == 0) + continue; + if (bytes_read < 0) + { + Error( "Problem during reading: %s", strerror(errno)); + close(fd); + return( false ); + } + if ( fwrite( buffer, bytes_read, 1, stdout ) != 1){ + Error( "Problem during writing: %s", strerror(errno)); + close(fd); + return( false ); + } + fflush( stdout ); + } + close(fd); + return ( true ); +} + +void FifoStream::file_create_if_missing(const char * path, bool is_fifo,bool delete_fake_fifo){ + static struct stat st; + if(stat(path,&st) == 0){ + + if (! is_fifo || S_ISFIFO(st.st_mode) || ! delete_fake_fifo) + return; + Debug(5, "Supposed to be a fifo pipe but isn't, unlinking: %s", path); + unlink(path); + } + int fd; + if (! is_fifo){ + Debug(5, "Creating non fifo file as requested: %s", path); + fd = open(path,O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR); + close(fd); + return; + } + Debug(5, "Making fifo file of: %s", path); + mkfifo(path,S_IRUSR|S_IWUSR); +} +void FifoStream::fifo_create_if_missing(const char * path, bool delete_fake_fifo){ + file_create_if_missing(path,true,delete_fake_fifo); +} +bool FifoStream::sendMJEGFrames(){ + static unsigned char buffer[ZM_MAX_IMAGE_SIZE]; + int fd = open(stream_path,O_RDONLY); + if (fd < 0) + { + Error( "Can't open %s: %s", stream_path, strerror(errno)); + return( false ); + } + total_read = 0; + while( (bytes_read = read(fd,buffer+total_read,ZM_MAX_IMAGE_SIZE-total_read)) ) + { + if (bytes_read < 0) + { + Error( "Problem during reading: %s", strerror(errno)); + close(fd); + return( false ); + } + total_read+=bytes_read; + } + close(fd); + if (total_read == 0) + return( true ); + if (frame_count%frame_mod != 0) + return (true ); + if (fprintf( stdout, "--ZoneMinderFrame\r\n" ) < 0 ) + { + Error( "Problem during writing: %s", strerror(errno)); + return( false ); + } + + fprintf( stdout, "Content-Type: image/jpeg\r\n" ); + fprintf( stdout, "Content-Length: %d\r\n\r\n", total_read ); + if ( fwrite( buffer, total_read, 1, stdout ) != 1){ + Error( "Problem during reading: %s", strerror(errno)); + return( false ); + } + fprintf( stdout, "\r\n\r\n" ); + fflush( stdout); + last_frame_sent = TV_2_FLOAT( now ); + frame_count++; + return( true ); +} + +void FifoStream::setStreamStart( const char * path ){ + stream_path = strdup(path); +} +void FifoStream::setStreamStart( int monitor_id, const char * format ){ + char diag_path[PATH_MAX]; + const char * filename; + Monitor * monitor = Monitor::Load(monitor_id, false, Monitor::QUERY); + + if (! strcmp(format,"reference") ) + { + stream_type = MJPEG; + filename = "diagpipe-r.jpg"; + } + else if (! strcmp(format,"delta")) + { + filename = "diagpipe-d.jpg"; + stream_type = MJPEG; + } + else + { + stream_type = RAW; + filename = "dbgpipe.log"; + } + + snprintf( diag_path, sizeof(diag_path), "%s/%d/%s", monitor->getStorage()->Path(), monitor->Id(), filename ); + setStreamStart(diag_path); +} +void FifoStream::runStream(){ + if (stream_type == MJPEG) + fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); + else + fprintf( stdout, "Content-Type: text/html\r\n\r\n" ); + + char lock_file[PATH_MAX]; + strcpy(lock_file,stream_path); + strcat(lock_file,".rlock"); + file_create_if_missing(lock_file,false); + int fd_lock = open(lock_file,O_RDONLY); + if (fd_lock < 0) + { + Error( "Can't open %s: %s", lock_file, strerror(errno)); + return; + } + int res = flock(fd_lock,LOCK_EX | LOCK_NB); + if (res < 0) + { + Error( "Flocking problem on %s: - %s", lock_file, strerror(errno) ); + close(fd_lock); + return; + } + + while( !zm_terminate ) + { + gettimeofday( &now, NULL ); + checkCommandQueue(); + if (stream_type == MJPEG) + { + if (! sendMJEGFrames()) + zm_terminate = true; + } + else + { + if (! sendRAWFrames()) + zm_terminate = true; + } + } + close(fd_lock); +} diff --git a/src/zm_fifo.h b/src/zm_fifo.h new file mode 100644 index 0000000000..8d1b1ae8c5 --- /dev/null +++ b/src/zm_fifo.h @@ -0,0 +1,61 @@ +#ifndef ZM_FIFO_H +#define ZM_FIFO_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zm.h" +#include "zm_image.h" +#include "zm_monitor.h" +#include "zm_stream.h" + + +#define zmFifoDbgPrintf(level,params...) {\ + zmFifoDbgOutput( 0, __FILE__, __LINE__, level, ##params );\ + } + +#ifndef ZM_DBG_OFF +#define FifoDebug(level,params...) zmFifoDbgPrintf(level,##params) +#else +#define FifoDebug(level,params...) +#endif +void zmFifoDbgOutput( int hex, const char * const file, const int line, const int level, const char *fstring, ... ) __attribute__ ((format(printf, 5, 6))); +int zmFifoDbgInit(Monitor * monitor); + +class FifoStream : public StreamBase +{ + +private: + char * stream_path; + int fd; + int total_read; + int bytes_read; + unsigned int frame_count; + static void file_create_if_missing(const char * path, bool is_fifo, bool delete_fake_fifo=true); + +protected: + typedef enum { MJPEG, RAW } StreamType; + StreamType stream_type; + bool sendMJEGFrames( ); + bool sendRAWFrames( ); + void processCommand( const CmdMsg *msg ) {}; + +public: + FifoStream(){ + + + } + static void fifo_create_if_missing(const char * path,bool delete_fake_fifo=true); + void setStreamStart( const char * path ); + void setStreamStart( int monitor_id, const char * format ); + + void runStream(); +}; +#endif diff --git a/src/zm_image.cpp b/src/zm_image.cpp index e58e403424..12c3da86ea 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -24,6 +24,7 @@ #include "zm_rgb.h" #include "zm_ffmpeg.h" +#include #include #include @@ -957,7 +958,7 @@ cinfo->out_color_space = JCS_RGB; return( true ); } -// Multiple calling formats to permit inclusion (or not) of both quality_override and timestamp (exif), with suitable defaults. +// Multiple calling formats to permit inclusion (or not) of non blocking, quality_override and timestamp (exif), with suitable defaults. // Note quality=zero means default bool Image::WriteJpeg(const char *filename, int quality_override) const { @@ -966,33 +967,71 @@ bool Image::WriteJpeg(const char *filename, int quality_override) const { bool Image::WriteJpeg(const char *filename) const { return Image::WriteJpeg(filename, 0, (timeval){0,0}); } +bool Image::WriteJpeg(const char *filename, bool on_blocking_abort) const { + return Image::WriteJpeg(filename, 0, (timeval){0,0}, on_blocking_abort); +} bool Image::WriteJpeg(const char *filename, struct timeval timestamp) const { return Image::WriteJpeg(filename, 0, timestamp); } bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval timestamp) const { + return Image::WriteJpeg(filename, quality_override, timestamp, false); +} +bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval timestamp, bool on_blocking_abort) const { if ( config.colour_jpeg_files && colours == ZM_COLOUR_GRAY8 ) { Image temp_image(*this); temp_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB); - return temp_image.WriteJpeg(filename, quality_override, timestamp); + return temp_image.WriteJpeg(filename, quality_override, timestamp, on_blocking_abort); } int quality = quality_override?quality_override:config.jpeg_file_quality; struct jpeg_compress_struct *cinfo = writejpg_ccinfo[quality]; + FILE *outfile =NULL; + static int raw_fd = 0; + bool need_create_comp = false; + raw_fd = 0; if ( !cinfo ) { cinfo = writejpg_ccinfo[quality] = new jpeg_compress_struct; cinfo->err = jpeg_std_error( &jpg_err.pub ); - jpg_err.pub.error_exit = zm_jpeg_error_exit; - jpg_err.pub.emit_message = zm_jpeg_emit_message; jpeg_create_compress( cinfo ); + need_create_comp=true; } + if (! on_blocking_abort) { + jpg_err.pub.error_exit = zm_jpeg_error_exit; + jpg_err.pub.emit_message = zm_jpeg_emit_message; + } else { + jpg_err.pub.error_exit = zm_jpeg_error_silent; + jpg_err.pub.emit_message = zm_jpeg_emit_silence; + if (setjmp( jpg_err.setjmp_buffer ) ) { + jpeg_abort_compress( cinfo ); + Debug( 5, "Aborted a write mid-stream and %s and %d", (outfile == NULL) ? "closing file" : "file not opened", raw_fd ); + if (raw_fd) + close(raw_fd); + if (outfile) + fclose( outfile ); + return ( false ); + } + } + if (need_create_comp) + jpeg_create_compress( cinfo ); - FILE *outfile; - if ( (outfile = fopen(filename, "wb")) == NULL ) { - Error("Can't open %s: %s", filename, strerror(errno)); - return false; + if (! on_blocking_abort) { + if ( (outfile = fopen(filename, "wb")) == NULL ) { + Error( "Can't open %s for writing: %s", filename, strerror(errno) ); + return false; + } + } else { + raw_fd = open(filename,O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + if (raw_fd < 0) + return ( false ); + outfile = fdopen(raw_fd,"wb"); + if (outfile == NULL) { + close(raw_fd); + return( false ); + } } + jpeg_stdio_dest( cinfo, outfile ); cinfo->image_width = width; /* image width and height, in pixels */ diff --git a/src/zm_image.h b/src/zm_image.h index 7133d0e358..d90d7c3584 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -218,9 +218,12 @@ class Image { bool ReadJpeg( const char *filename, unsigned int p_colours, unsigned int p_subpixelorder); bool WriteJpeg ( const char *filename) const; + bool WriteJpeg ( const char *filename, bool on_blocking_abort) const; bool WriteJpeg ( const char *filename, int quality_override ) const; bool WriteJpeg ( const char *filename, struct timeval timestamp ) const; bool WriteJpeg ( const char *filename, int quality_override, struct timeval timestamp ) const; + bool WriteJpeg ( const char *filename, int quality_override, struct timeval timestamp, bool on_blocking_abort ) const; + bool DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, unsigned int p_colours, unsigned int p_subpixelorder); bool EncodeJpeg( JOCTET *outbuffer, int *outbuffer_size, int quality_override=0 ) const; diff --git a/src/zm_jpeg.cpp b/src/zm_jpeg.cpp index cddf086c5f..8e88992276 100644 --- a/src/zm_jpeg.cpp +++ b/src/zm_jpeg.cpp @@ -30,6 +30,13 @@ extern "C" static int jpeg_err_count = 0; +void zm_jpeg_error_silent( j_common_ptr cinfo ){ + zm_error_ptr zmerr = (zm_error_ptr)cinfo->err; + longjmp( zmerr->setjmp_buffer, 1 ); +} +void zm_jpeg_emit_silence( j_common_ptr cinfo, int msg_level ){ +} + void zm_jpeg_error_exit( j_common_ptr cinfo ) { static char buffer[JMSG_LENGTH_MAX]; diff --git a/src/zm_jpeg.h b/src/zm_jpeg.h index d0348dd3ea..f0b4a355c2 100644 --- a/src/zm_jpeg.h +++ b/src/zm_jpeg.h @@ -38,6 +38,8 @@ struct zm_error_mgr typedef struct zm_error_mgr *zm_error_ptr; +void zm_jpeg_error_silent( j_common_ptr cinfo ); +void zm_jpeg_emit_silence( j_common_ptr cinfo, int msg_level ); void zm_jpeg_error_exit( j_common_ptr cinfo ); void zm_jpeg_emit_message( j_common_ptr cinfo, int msg_level ); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 2987d08f27..99416b6586 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -44,6 +44,7 @@ #if HAVE_LIBAVFORMAT #include "zm_ffmpeg_camera.h" #endif // HAVE_LIBAVFORMAT +#include "zm_fifo.h" #if HAVE_LIBVLC #include "zm_libvlc_camera.h" #endif // HAVE_LIBVLC @@ -517,8 +518,12 @@ Monitor::Monitor( ReloadLinkedMonitors(p_linked_monitors); if ( config.record_diag_images ) { - diag_path_r = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); - diag_path_d = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); + diag_path_r = stringtf(config.record_diag_images_fifo ? "%s/%d/diagpipe-r.jpg" : "%s/%d/diag-r.jpg", storage->Path(), id); + diag_path_d = stringtf(config.record_diag_images_fifo ? "%s/%d/diagpipe-d.jpg" : "%s/%d/diag-d.jpg", storage->Path(), id); + if (config.record_diag_images_fifo){ + FifoStream::fifo_create_if_missing(diag_path_r.c_str()); + FifoStream::fifo_create_if_missing(diag_path_d.c_str()); + } } } // end if purpose == ANALYSIS @@ -2614,8 +2619,8 @@ unsigned int Monitor::DetectMotion(const Image &comp_image, Event::StringSet &zo ref_image.Delta(comp_image, &delta_image); if ( config.record_diag_images ) { - ref_image.WriteJpeg(diag_path_r.c_str()); - delta_image.WriteJpeg(diag_path_d.c_str()); + ref_image.WriteJpeg(diag_path_r.c_str(), config.record_diag_images_fifo); + delta_image.WriteJpeg(diag_path_d.c_str(), config.record_diag_images_fifo); } // Blank out all exclusion zones diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 6d4ae15e3e..de2f8003d9 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -24,6 +24,7 @@ #include "zm_zone.h" #include "zm_image.h" #include "zm_monitor.h" +#include "zm_fifo.h" void Zone::Setup( @@ -112,8 +113,10 @@ void Zone::Setup( } if ( config.record_diag_images ) { - snprintf(diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); - pg_image->WriteJpeg(diag_path); + snprintf(diag_path, sizeof(diag_path), config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); + if (config.record_diag_images_fifo) + FifoStream::fifo_create_if_missing(diag_path); + pg_image->WriteJpeg(diag_path, config.record_diag_images_fifo); } else { diag_path[0] = 0; } @@ -232,7 +235,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { std_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count); if ( config.record_diag_images ) - diff_image->WriteJpeg(diag_path); + diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo); if ( pixel_diff_count && alarm_pixels ) pixel_diff = pixel_diff_count/alarm_pixels; @@ -240,6 +243,10 @@ bool Zone::CheckAlarms(const Image *delta_image) { Debug(5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff); + if (config.record_diag_images_fifo) + FifoDebug( 5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}", id,alarm_pixels, pixel_diff ); + + if ( alarm_pixels ) { if ( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) { /* Not enough pixels alarmed */ @@ -316,11 +323,14 @@ bool Zone::CheckAlarms(const Image *delta_image) { } if ( config.record_diag_images ) - diff_image->WriteJpeg(diag_path); + diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo); Debug(5, "Got %d filtered pixels, need %d -> %d", alarm_filter_pixels, min_filter_pixels, max_filter_pixels); + if (config.record_diag_images_fifo) + FifoDebug( 5, "{\"zone\":%d,\"type\":\"FILT\",\"pixels\":%d}", id, alarm_filter_pixels ); + if ( alarm_filter_pixels ) { if ( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) { /* Not enough pixels alarmed */ @@ -542,7 +552,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { } } if ( config.record_diag_images ) - diff_image->WriteJpeg(diag_path); + diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo); if ( !alarm_blobs ) { return false; @@ -551,6 +561,9 @@ bool Zone::CheckAlarms(const Image *delta_image) { Debug(5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); + if (config.record_diag_images_fifo) + FifoDebug( 5, "{\"zone\":%d,\"type\":\"RBLB\",\"pixels\":%d,\"blobs\":%d}", id, alarm_blob_pixels, alarm_blobs ); + // Now eliminate blobs under the threshold for ( int i = 1; i < WHITE; i++ ) { BlobStats *bs = &blob_stats[i]; @@ -587,10 +600,12 @@ bool Zone::CheckAlarms(const Image *delta_image) { } // end if bs_count } // end for i < WHITE if ( config.record_diag_images ) - diff_image->WriteJpeg(diag_path); + diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo); Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); + if (config.record_diag_images_fifo) + FifoDebug( 5, "{\"zone\":%d,\"type\":\"FBLB\",\"pixels\":%d,\"blobs\":%d}", id, alarm_blob_pixels, alarm_blobs ); if ( alarm_blobs ) { if ( min_blobs && (alarm_blobs < min_blobs) ) { diff --git a/src/zma.cpp b/src/zma.cpp index 33dedbe54b..a0cb048bfd 100644 --- a/src/zma.cpp +++ b/src/zma.cpp @@ -56,6 +56,7 @@ behind. #include "zm_db.h" #include "zm_signal.h" #include "zm_monitor.h" +#include "zm_fifo.h" void Usage() { fprintf(stderr, "zma -m \n"); @@ -129,6 +130,7 @@ int main( int argc, char *argv[] ) { hwcaps_detect(); Monitor *monitor = Monitor::Load(id, true, Monitor::ANALYSIS); + zmFifoDbgInit( monitor ); if ( monitor ) { Info("In mode %d/%d, warming up", monitor->GetFunction(), monitor->Enabled()); diff --git a/src/zms.cpp b/src/zms.cpp index 0a37129389..6042dbef3d 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -28,6 +28,7 @@ #include "zm_monitor.h" #include "zm_monitorstream.h" #include "zm_eventstream.h" +#include "zm_fifo.h" bool ValidateAccess( User *user, int mon_id ) { bool allowed = true; @@ -54,7 +55,7 @@ int main( int argc, const char *argv[] ) { srand( getpid() * time( 0 ) ); - enum { ZMS_UNKNOWN, ZMS_MONITOR, ZMS_EVENT } source = ZMS_UNKNOWN; + enum { ZMS_UNKNOWN, ZMS_MONITOR, ZMS_EVENT, ZMS_FIFO } source = ZMS_UNKNOWN; enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_ZIP, ZMS_SINGLE } mode = ZMS_JPEG; char format[32] = ""; int monitor_id = 0; @@ -110,6 +111,8 @@ int main( int argc, const char *argv[] ) { value = (char *)""; if ( !strcmp(name, "source") ) { source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR; + if (! strcmp( value,"fifo") ) + source = ZMS_FIFO; } else if ( !strcmp(name, "mode") ) { mode = !strcmp(value, "jpeg")?ZMS_JPEG:ZMS_MPEG; mode = !strcmp(value, "raw")?ZMS_RAW:mode; @@ -274,6 +277,11 @@ int main( int argc, const char *argv[] ) { #endif // HAVE_LIBAVCODEC } stream.runStream(); + } else if (source == ZMS_FIFO ) { + FifoStream stream; + stream.setStreamMaxFPS( maxfps ); + stream.setStreamStart( monitor_id, format ); + stream.runStream(); } else if ( source == ZMS_EVENT ) { if ( ! event_id ) { Fatal( "Can't view an event without specifying an event_id." );