FIFO support for zoneminder zone debugging (#2594)

Adds fifo options for diagnostic images for much lower impact diagnostics mode.  Diagnostic images are only written when there is a client listening for them (otherwise they are skipped).  Also added a json stream for the detection data so you can see in real time the pixels or blobs detected for the motion.  This allows for easy real time stream of both delta and reference images (as video streams) along with the detection numbers.
pull/2616/head
Mitch Capper 2019-05-16 12:37:03 -07:00 committed by Isaac Connor
parent 4f44db8cbf
commit eb005e8b9c
12 changed files with 419 additions and 22 deletions

View File

@ -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;

View File

@ -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})

247
src/zm_fifo.cpp Normal file
View File

@ -0,0 +1,247 @@
#include <fcntl.h>
#include <getopt.h>
#include <sys/file.h>
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#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);
}

61
src/zm_fifo.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef ZM_FIFO_H
#define ZM_FIFO_H
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#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

View File

@ -24,6 +24,7 @@
#include "zm_rgb.h"
#include "zm_ffmpeg.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
@ -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 );
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 );
}
}
FILE *outfile;
if ( (outfile = fopen(filename, "wb")) == NULL ) {
Error("Can't open %s: %s", filename, strerror(errno));
return false;
}
jpeg_stdio_dest( cinfo, outfile );
cinfo->image_width = width; /* image width and height, in pixels */

View File

@ -218,9 +218,12 @@ public:
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;

View File

@ -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];

View File

@ -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 );

View File

@ -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

View File

@ -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) ) {

View File

@ -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 <monitor_id>\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());

View File

@ -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." );