forked from ZoneMinder/zoneminder
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FIFO support for zoneminder zone debugging (ZoneMinder#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.
- Loading branch information
1 parent
4f44db8
commit eb005e8
Showing
12 changed files
with
418 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.