Merge pull request #3314 from Carbenium/path-max

Fix Wformat for stringtf and convert path buffers depending on PATH_MAX to std::string
This commit is contained in:
Isaac Connor 2021-07-07 11:34:03 -04:00 committed by GitHub
commit b0cf3a4732
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 311 additions and 332 deletions

View File

@ -39,16 +39,15 @@ void zmLoadStaticConfig() {
// update the Config hash with those values // update the Config hash with those values
DIR *configSubFolder = opendir(ZM_CONFIG_SUBDIR); DIR *configSubFolder = opendir(ZM_CONFIG_SUBDIR);
if (configSubFolder) { // subfolder exists and is readable if (configSubFolder) { // subfolder exists and is readable
char glob_pattern[PATH_MAX] = ""; std::string glob_pattern = stringtf("%s/*.conf", ZM_CONFIG_SUBDIR);
snprintf(glob_pattern, sizeof(glob_pattern), "%s/*.conf", ZM_CONFIG_SUBDIR);
glob_t pglob; glob_t pglob;
int glob_status = glob(glob_pattern, 0, nullptr, &pglob); int glob_status = glob(glob_pattern.c_str(), 0, nullptr, &pglob);
if (glob_status != 0) { if (glob_status != 0) {
if (glob_status < 0) { if (glob_status < 0) {
Error("Can't glob '%s': %s", glob_pattern, strerror(errno)); Error("Can't glob '%s': %s", glob_pattern.c_str(), strerror(errno));
} else { } else {
Debug(1, "Can't glob '%s': %d", glob_pattern, glob_status); Debug(1, "Can't glob '%s': %d", glob_pattern.c_str(), glob_status);
} }
} else { } else {
for (unsigned int i = 0; i < pglob.gl_pathc; i++) { for (unsigned int i = 0; i < pglob.gl_pathc; i++) {
@ -100,13 +99,10 @@ void zmLoadDBConfig() {
} }
} }
snprintf(staticConfig.capture_file_format, sizeof(staticConfig.capture_file_format), "%%s/%%0%dd-capture.jpg", staticConfig.capture_file_format = stringtf("%%s/%%0%dd-capture.jpg", config.event_image_digits);
config.event_image_digits); staticConfig.analyse_file_format = stringtf("%%s/%%0%dd-analyse.jpg", config.event_image_digits);
snprintf(staticConfig.analyse_file_format, sizeof(staticConfig.analyse_file_format), "%%s/%%0%dd-analyse.jpg", staticConfig.general_file_format = stringtf("%%s/%%0%dd-%%s", config.event_image_digits);
config.event_image_digits); staticConfig.video_file_format = "%s/%s";
snprintf(staticConfig.general_file_format, sizeof(staticConfig.general_file_format), "%%s/%%0%dd-%%s",
config.event_image_digits);
snprintf(staticConfig.video_file_format, sizeof(staticConfig.video_file_format), "%%s/%%s");
} }
void process_configfile(char const *configFile) { void process_configfile(char const *configFile) {

View File

@ -25,10 +25,6 @@
#include "zm_config_defines.h" #include "zm_config_defines.h"
#include <string> #include <string>
#if !defined(PATH_MAX)
#define PATH_MAX 1024
#endif
#define ZM_MAX_IMAGE_WIDTH 2048 // The largest image we imagine ever handling #define ZM_MAX_IMAGE_WIDTH 2048 // The largest image we imagine ever handling
#define ZM_MAX_IMAGE_HEIGHT 1536 // The largest image we imagine ever handling #define ZM_MAX_IMAGE_HEIGHT 1536 // The largest image we imagine ever handling
#define ZM_MAX_IMAGE_COLOURS 4 // The largest image we imagine ever handling #define ZM_MAX_IMAGE_COLOURS 4 // The largest image we imagine ever handling
@ -69,10 +65,10 @@ struct StaticConfig {
std::string PATH_LOGS; std::string PATH_LOGS;
std::string PATH_SWAP; std::string PATH_SWAP;
std::string PATH_ARP; std::string PATH_ARP;
char capture_file_format[PATH_MAX]; std::string capture_file_format;
char analyse_file_format[PATH_MAX]; std::string analyse_file_format;
char general_file_format[PATH_MAX]; std::string general_file_format;
char video_file_format[PATH_MAX]; std::string video_file_format;
}; };
extern StaticConfig staticConfig; extern StaticConfig staticConfig;

View File

@ -466,7 +466,7 @@ void Event::AddFrame(Image *image,
if (image) { if (image) {
if (save_jpegs & 1) { if (save_jpegs & 1) {
std::string event_file = stringtf(staticConfig.capture_file_format, path.c_str(), frames); std::string event_file = stringtf(staticConfig.capture_file_format.c_str(), path.c_str(), frames);
Debug(1, "Writing capture frame %d to %s", frames, event_file.c_str()); Debug(1, "Writing capture frame %d to %s", frames, event_file.c_str());
if (!WriteFrameImage(image, timestamp, event_file.c_str())) { if (!WriteFrameImage(image, timestamp, event_file.c_str())) {
Error("Failed to write frame image"); Error("Failed to write frame image");
@ -496,7 +496,7 @@ void Event::AddFrame(Image *image,
} }
if (alarm_image and (save_jpegs & 2)) { if (alarm_image and (save_jpegs & 2)) {
std::string event_file = stringtf(staticConfig.analyse_file_format, path.c_str(), frames); std::string event_file = stringtf(staticConfig.analyse_file_format.c_str(), path.c_str(), frames);
Debug(1, "Writing analysis frame %d", frames); Debug(1, "Writing analysis frame %d", frames);
if (!WriteFrameImage(alarm_image, timestamp, event_file.c_str(), true)) { if (!WriteFrameImage(alarm_image, timestamp, event_file.c_str(), true)) {
Error("Failed to write analysis frame image"); Error("Failed to write analysis frame image");

View File

@ -24,6 +24,7 @@
#include "zm_define.h" #include "zm_define.h"
#include "zm_storage.h" #include "zm_storage.h"
#include "zm_time.h" #include "zm_time.h"
#include "zm_utils.h"
#include "zm_zone.h" #include "zm_zone.h"
#include <map> #include <map>
@ -128,18 +129,17 @@ class Event {
bool SetPath(Storage *storage); bool SetPath(Storage *storage);
public: public:
static const char *getSubPath(tm time) { static std::string getSubPath(tm time) {
static char subpath[PATH_MAX] = ""; std::string subpath = stringtf("%02d/%02d/%02d/%02d/%02d/%02d",
snprintf(subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time.tm_year - 100, time.tm_mon + 1, time.tm_mday,
time.tm_year-100, time.tm_mon+1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
time.tm_hour, time.tm_min, time.tm_sec); return subpath;
return subpath; }
} static std::string getSubPath(time_t *time) {
static const char *getSubPath(time_t *time) { tm time_tm = {};
tm time_tm = {}; localtime_r(time, &time_tm);
localtime_r(time, &time_tm); return Event::getSubPath(time_tm);
return Event::getSubPath(time_tm); }
}
const char* getEventFile() const { const char* getEventFile() const {
return video_file.c_str(); return video_file.c_str();

View File

@ -44,7 +44,7 @@ constexpr Milliseconds EventStream::STREAM_PAUSE_WAIT;
bool EventStream::loadInitialEventData(int monitor_id, SystemTimePoint event_time) { bool EventStream::loadInitialEventData(int monitor_id, SystemTimePoint event_time) {
std::string sql = stringtf("SELECT `Id` FROM `Events` WHERE " std::string sql = stringtf("SELECT `Id` FROM `Events` WHERE "
"`MonitorId` = %d AND unix_timestamp(`EndDateTime`) > %ld " "`MonitorId` = %d AND unix_timestamp(`EndDateTime`) > %ld "
"ORDER BY `Id` ASC LIMIT 1", monitor_id, event_time); "ORDER BY `Id` ASC LIMIT 1", monitor_id, std::chrono::system_clock::to_time_t(event_time));
MYSQL_RES *result = zmDbFetch(sql); MYSQL_RES *result = zmDbFetch(sql);
if (!result) if (!result)
@ -145,7 +145,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
event_data->duration = std::chrono::duration_cast<Microseconds>(event_data->end_time - event_data->start_time); event_data->duration = std::chrono::duration_cast<Microseconds>(event_data->end_time - event_data->start_time);
event_data->frames_duration = event_data->frames_duration =
std::chrono::duration_cast<Microseconds>(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0)); std::chrono::duration_cast<Microseconds>(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0));
strncpy(event_data->video_file, dbrow[6], sizeof(event_data->video_file) - 1); event_data->video_file = std::string(dbrow[6]);
std::string scheme_str = std::string(dbrow[7]); std::string scheme_str = std::string(dbrow[7]);
if ( scheme_str == "Deep" ) { if ( scheme_str == "Deep" ) {
event_data->scheme = Storage::DEEP; event_data->scheme = Storage::DEEP;
@ -180,44 +180,41 @@ bool EventStream::loadEventData(uint64_t event_id) {
time_t start_time_t = std::chrono::system_clock::to_time_t(event_data->start_time); time_t start_time_t = std::chrono::system_clock::to_time_t(event_data->start_time);
localtime_r(&start_time_t, &event_time); localtime_r(&start_time_t, &event_time);
if ( storage_path[0] == '/' ) if (storage_path[0] == '/') {
snprintf(event_data->path, sizeof(event_data->path), event_data->path = stringtf("%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
"%s/%u/%02d/%02d/%02d/%02d/%02d/%02d", storage_path, event_data->monitor_id,
storage_path, event_data->monitor_id, event_time.tm_year - 100, event_time.tm_mon + 1, event_time.tm_mday,
event_time.tm_year-100, event_time.tm_mon+1, event_time.tm_mday, event_time.tm_hour, event_time.tm_min, event_time.tm_sec);
event_time.tm_hour, event_time.tm_min, event_time.tm_sec); } else {
else event_data->path = stringtf("%s/%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
snprintf(event_data->path, sizeof(event_data->path), staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
"%s/%s/%u/%02d/%02d/%02d/%02d/%02d/%02d", event_time.tm_year - 100, event_time.tm_mon + 1, event_time.tm_mday,
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time.tm_hour, event_time.tm_min, event_time.tm_sec);
event_time.tm_year-100, event_time.tm_mon+1, event_time.tm_mday, }
event_time.tm_hour, event_time.tm_min, event_time.tm_sec); } else if (event_data->scheme == Storage::MEDIUM) {
} else if ( event_data->scheme == Storage::MEDIUM ) {
tm event_time = {}; tm event_time = {};
time_t start_time_t = std::chrono::system_clock::to_time_t(event_data->start_time); time_t start_time_t = std::chrono::system_clock::to_time_t(event_data->start_time);
localtime_r(&start_time_t, &event_time); localtime_r(&start_time_t, &event_time);
if ( storage_path[0] == '/' ) if (storage_path[0] == '/') {
snprintf(event_data->path, sizeof(event_data->path), event_data->path = stringtf("%s/%u/%04d-%02d-%02d/%" PRIu64,
"%s/%u/%04d-%02d-%02d/%" PRIu64, storage_path, event_data->monitor_id,
storage_path, event_data->monitor_id, event_time.tm_year + 1900, event_time.tm_mon + 1, event_time.tm_mday,
event_time.tm_year+1900, event_time.tm_mon+1, event_time.tm_mday, event_data->event_id);
event_data->event_id); } else {
else event_data->path = stringtf("%s/%s/%u/%04d-%02d-%02d/%" PRIu64,
snprintf(event_data->path, sizeof(event_data->path), staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
"%s/%s/%u/%04d-%02d-%02d/%" PRIu64, event_time.tm_year + 1900, event_time.tm_mon + 1, event_time.tm_mday,
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id);
event_time.tm_year+1900, event_time.tm_mon+1, event_time.tm_mday, }
event_data->event_id);
} else { } else {
if ( storage_path[0] == '/' ) if (storage_path[0] == '/') {
snprintf(event_data->path, sizeof(event_data->path), "%s/%u/%" PRIu64, event_data->path = stringtf("%s/%u/%" PRIu64, storage_path, event_data->monitor_id, event_data->event_id);
storage_path, event_data->monitor_id, event_data->event_id); } else {
else event_data->path = stringtf("%s/%s/%u/%" PRIu64,
snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%u/%" PRIu64, staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id);
event_data->event_id); }
} }
double fps = 1.0; double fps = 1.0;
@ -289,17 +286,17 @@ bool EventStream::loadEventData(uint64_t event_id) {
} }
mysql_free_result(result); mysql_free_result(result);
if ( event_data->video_file[0] || (monitor->GetOptVideoWriter() > 0) ) { if (!event_data->video_file.empty() || (monitor->GetOptVideoWriter() > 0)) {
if ( !event_data->video_file[0] ) { if (event_data->video_file.empty()) {
snprintf(event_data->video_file, sizeof(event_data->video_file), "%" PRIu64 "-%s", event_data->event_id, "video.mp4"); event_data->video_file = stringtf("%" PRIu64 "-%s", event_data->event_id, "video.mp4");
} }
std::string filepath = std::string(event_data->path) + "/" + std::string(event_data->video_file);
std::string filepath = event_data->path + "/" + event_data->video_file;
Debug(1, "Loading video file from %s", filepath.c_str()); Debug(1, "Loading video file from %s", filepath.c_str());
if ( ffmpeg_input ) delete ffmpeg_input;
delete ffmpeg_input;
ffmpeg_input = new FFmpeg_Input(); ffmpeg_input = new FFmpeg_Input();
if ( 0 > ffmpeg_input->Open(filepath.c_str()) ) { if (ffmpeg_input->Open(filepath.c_str()) < 0) {
Warning("Unable to open ffmpeg_input %s", filepath.c_str()); Warning("Unable to open ffmpeg_input %s", filepath.c_str());
delete ffmpeg_input; delete ffmpeg_input;
ffmpeg_input = nullptr; ffmpeg_input = nullptr;
@ -690,32 +687,30 @@ bool EventStream::checkEventLoaded() {
} // void EventStream::checkEventLoaded() } // void EventStream::checkEventLoaded()
Image * EventStream::getImage( ) { Image * EventStream::getImage( ) {
static char filepath[PATH_MAX]; std::string path = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
Debug(2, "EventStream::getImage path(%s) from %s frame(%ld) ", path.c_str(), event_data->path.c_str(), curr_frame_id);
snprintf(filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id); Image *image = new Image(path.c_str());
Debug(2, "EventStream::getImage path(%s) from %s frame(%ld) ", filepath, event_data->path, curr_frame_id);
Image *image = new Image(filepath);
return image; return image;
} }
bool EventStream::sendFrame(Microseconds delta_us) { bool EventStream::sendFrame(Microseconds delta_us) {
Debug(2, "Sending frame %ld", curr_frame_id); Debug(2, "Sending frame %ld", curr_frame_id);
static char filepath[PATH_MAX]; std::string filepath;
static struct stat filestat; struct stat filestat = {};
// This needs to be abstracted. If we are saving jpgs, then load the capture file. // This needs to be abstracted. If we are saving jpgs, then load the capture file.
// If we are only saving analysis frames, then send that. // If we are only saving analysis frames, then send that.
if ( event_data->SaveJPEGs & 1 ) { if (event_data->SaveJPEGs & 1) {
snprintf(filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id); filepath = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
} else if ( event_data->SaveJPEGs & 2 ) { } else if (event_data->SaveJPEGs & 2) {
snprintf(filepath, sizeof(filepath), staticConfig.analyse_file_format, event_data->path, curr_frame_id); filepath = stringtf(staticConfig.analyse_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
if ( stat(filepath, &filestat) < 0 ) { if (stat(filepath.c_str(), &filestat) < 0) {
Debug(1, "analyze file %s not found will try to stream from other", filepath); Debug(1, "analyze file %s not found will try to stream from other", filepath.c_str());
snprintf(filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id); filepath = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
if ( stat(filepath, &filestat) < 0 ) { if (stat(filepath.c_str(), &filestat) < 0) {
Debug(1, "capture file %s not found either", filepath); Debug(1, "capture file %s not found either", filepath.c_str());
filepath[0] = 0; filepath = "";
} }
} }
} else if ( !ffmpeg_input ) { } else if ( !ffmpeg_input ) {
@ -724,7 +719,7 @@ bool EventStream::sendFrame(Microseconds delta_us) {
} }
if ( type == STREAM_MPEG ) { if ( type == STREAM_MPEG ) {
Image image(filepath); Image image(filepath.c_str());
Image *send_image = prepareImage(&image); Image *send_image = prepareImage(&image);
@ -739,20 +734,20 @@ bool EventStream::sendFrame(Microseconds delta_us) {
config.mpeg_timed_frames, config.mpeg_timed_frames,
delta_us.count() * 1000); delta_us.count() * 1000);
} else { } else {
bool send_raw = (type == STREAM_JPEG) && ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0]; bool send_raw = (type == STREAM_JPEG) && ((scale >= ZM_SCALE_BASE) && (zoom == ZM_SCALE_BASE)) && !filepath.empty();
fprintf(stdout, "--" BOUNDARY "\r\n"); fprintf(stdout, "--" BOUNDARY "\r\n");
if ( send_raw ) { if (send_raw) {
if ( !send_file(filepath) ) { if (!send_file(filepath)) {
Error("Can't send %s: %s", filepath, strerror(errno)); Error("Can't send %s: %s", filepath.c_str(), strerror(errno));
return false; return false;
} }
} else { } else {
Image *image = nullptr; Image *image = nullptr;
if ( filepath[0] ) { if (!filepath.empty()) {
image = new Image(filepath); image = new Image(filepath.c_str());
} else if ( ffmpeg_input ) { } else if ( ffmpeg_input ) {
// Get the frame from the mp4 input // Get the frame from the mp4 input
FrameData *frame_data = &event_data->frames[curr_frame_id-1]; FrameData *frame_data = &event_data->frames[curr_frame_id-1];
@ -1088,24 +1083,24 @@ void EventStream::runStream() {
closeComms(); closeComms();
} // end void EventStream::runStream() } // end void EventStream::runStream()
bool EventStream::send_file(const char *filepath) { bool EventStream::send_file(const std::string &filepath) {
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; int img_buffer_size = 0;
uint8_t *img_buffer = temp_img_buffer; uint8_t *img_buffer = temp_img_buffer;
FILE *fdj = nullptr; FILE *fdj = nullptr;
fdj = fopen(filepath, "rb"); fdj = fopen(filepath.c_str(), "rb");
if ( !fdj ) { if ( !fdj ) {
Error("Can't open %s: %s", filepath, strerror(errno)); Error("Can't open %s: %s", filepath.c_str(), strerror(errno));
std::string error_message = stringtf("Can't open %s: %s", filepath, strerror(errno)); std::string error_message = stringtf("Can't open %s: %s", filepath.c_str(), strerror(errno));
return sendTextFrame(error_message.c_str()); return sendTextFrame(error_message.c_str());
} }
#if HAVE_SENDFILE #if HAVE_SENDFILE
static struct stat filestat; static struct stat filestat;
if ( fstat(fileno(fdj), &filestat) < 0 ) { if ( fstat(fileno(fdj), &filestat) < 0 ) {
fclose(fdj); /* Close the file handle */ fclose(fdj); /* Close the file handle */
Error("Failed getting information about file %s: %s", filepath, strerror(errno)); Error("Failed getting information about file %s: %s", filepath.c_str(), strerror(errno));
return false; return false;
} }
if ( !filestat.st_size ) { if ( !filestat.st_size ) {
@ -1134,7 +1129,7 @@ bool EventStream::send_file(const char *filepath) {
} }
return send_buffer(img_buffer, img_buffer_size); return send_buffer(img_buffer, img_buffer_size);
} // end bool EventStream::send_file(const char * filepath) }
bool EventStream::send_buffer(uint8_t* buffer, int size) { bool EventStream::send_buffer(uint8_t* buffer, int size) {
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", size) ) { if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", size) ) {

View File

@ -56,10 +56,10 @@ class EventStream : public StreamBase {
SystemTimePoint end_time; SystemTimePoint end_time;
Microseconds duration; Microseconds duration;
Microseconds frames_duration; Microseconds frames_duration;
char path[PATH_MAX]; std::string path;
int n_frames; // # of frame rows returned from database int n_frames; // # of frame rows returned from database
FrameData *frames; FrameData *frames;
char video_file[PATH_MAX]; std::string video_file;
Storage::Schemes scheme; Storage::Schemes scheme;
int SaveJPEGs; int SaveJPEGs;
Monitor::Orientation Orientation; Monitor::Orientation Orientation;
@ -124,7 +124,7 @@ class EventStream : public StreamBase {
void runStream() override; void runStream() override;
Image *getImage(); Image *getImage();
private: private:
bool send_file(const char *filepath); bool send_file(const std::string &filepath);
bool send_buffer(uint8_t * buffer, int size); bool send_buffer(uint8_t * buffer, int size);
Storage *storage; Storage *storage;
FFmpeg_Input *ffmpeg_input; FFmpeg_Input *ffmpeg_input;

View File

@ -29,32 +29,26 @@
#define RAW_BUFFER 512 #define RAW_BUFFER 512
#define PIPE_SIZE 1024*1024 #define PIPE_SIZE 1024*1024
void Fifo::file_create_if_missing( void Fifo::file_create_if_missing(const std::string &path, bool is_fifo, bool delete_fake_fifo) {
const char * path, struct stat st = {};
bool is_fifo,
bool delete_fake_fifo if (stat(path.c_str(), &st) == 0) {
) { if ((!is_fifo) || S_ISFIFO(st.st_mode) || !delete_fake_fifo)
static struct stat st;
if ( stat(path, &st) == 0 ) {
if ( (!is_fifo) || S_ISFIFO(st.st_mode) || !delete_fake_fifo )
return; return;
Debug(5, "Supposed to be a fifo pipe but isn't, unlinking: %s", path); Debug(5, "Supposed to be a fifo pipe but isn't, unlinking: %s", path.c_str());
unlink(path); unlink(path.c_str());
} }
if (!is_fifo) { if (!is_fifo) {
Debug(5, "Creating non fifo file as requested: %s", path); Debug(5, "Creating non fifo file as requested: %s", path.c_str());
int fd = ::open(path, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); int fd = ::open(path.c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
::close(fd); ::close(fd);
return; return;
} }
Debug(5, "Making fifo file of: %s", path); Debug(5, "Making fifo file of: %s", path.c_str());
mkfifo(path, S_IRUSR|S_IWUSR); mkfifo(path.c_str(), S_IRUSR | S_IWUSR);
} }
void Fifo::fifo_create_if_missing( void Fifo::fifo_create_if_missing(const std::string &path, bool delete_fake_fifo) {
const char * path,
bool delete_fake_fifo
) {
file_create_if_missing(path, true, delete_fake_fifo); file_create_if_missing(path, true, delete_fake_fifo);
} }
@ -62,7 +56,8 @@ Fifo::~Fifo() {
close(); close();
} }
bool Fifo::open() { bool Fifo::open() {
fifo_create_if_missing(path.c_str()); fifo_create_if_missing(path);
if (!on_blocking_abort) { if (!on_blocking_abort) {
if ( (outfile = fopen(path.c_str(), "wb")) == nullptr ) { if ( (outfile = fopen(path.c_str(), "wb")) == nullptr ) {
Error("Can't open %s for writing: %s", path.c_str(), strerror(errno)); Error("Can't open %s for writing: %s", path.c_str(), strerror(errno));

View File

@ -32,11 +32,8 @@ class Fifo {
int raw_fd; int raw_fd;
public: public:
static void file_create_if_missing( static void file_create_if_missing(const std::string &path, bool is_fifo, bool delete_fake_fifo = true);
const char * path, static void fifo_create_if_missing(const std::string &path, bool delete_fake_fifo = true);
bool is_fifo,
bool delete_fake_fifo = true
);
Fifo() : Fifo() :
on_blocking_abort(true), on_blocking_abort(true),
@ -51,12 +48,6 @@ class Fifo {
{} {}
~Fifo(); ~Fifo();
static void fifo_create_if_missing(
const char * path,
bool delete_fake_fifo = true);
static bool writePacket(std::string filename, const ZMPacket &packet); static bool writePacket(std::string filename, const ZMPacket &packet);
static bool write(std::string filename, uint8_t *data, size_t size); static bool write(std::string filename, uint8_t *data, size_t size);

View File

@ -28,7 +28,7 @@
#define RAW_BUFFER 512 #define RAW_BUFFER 512
static bool zm_fifodbg_inited = false; static bool zm_fifodbg_inited = false;
FILE *zm_fifodbg_log_fd = nullptr; FILE *zm_fifodbg_log_fd = nullptr;
char zm_fifodbg_log[PATH_MAX] = ""; std::string zm_fifodbg_log;
static bool zmFifoDbgOpen() { static bool zmFifoDbgOpen() {
if ( zm_fifodbg_log_fd ) if ( zm_fifodbg_log_fd )
@ -36,7 +36,7 @@ static bool zmFifoDbgOpen() {
zm_fifodbg_log_fd = nullptr; zm_fifodbg_log_fd = nullptr;
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
Fifo::fifo_create_if_missing(zm_fifodbg_log); Fifo::fifo_create_if_missing(zm_fifodbg_log);
int fd = open(zm_fifodbg_log, O_WRONLY|O_NONBLOCK|O_TRUNC); int fd = open(zm_fifodbg_log.c_str(), O_WRONLY | O_NONBLOCK | O_TRUNC);
if ( fd < 0 ) if ( fd < 0 )
return false; return false;
int res = flock(fd, LOCK_EX | LOCK_NB); int res = flock(fd, LOCK_EX | LOCK_NB);
@ -54,8 +54,7 @@ static bool zmFifoDbgOpen() {
int zmFifoDbgInit(Monitor *monitor) { int zmFifoDbgInit(Monitor *monitor) {
zm_fifodbg_inited = true; zm_fifodbg_inited = true;
snprintf(zm_fifodbg_log, sizeof(zm_fifodbg_log), "%s/dbgpipe-%u.log", zm_fifodbg_log = stringtf("%s/dbgpipe-%u.log", staticConfig.PATH_SOCKS.c_str(), monitor->Id());
staticConfig.PATH_SOCKS.c_str(), monitor->Id());
zmFifoDbgOpen(); zmFifoDbgOpen();
return 1; return 1;
} }

View File

@ -29,9 +29,9 @@
#define RAW_BUFFER 512 #define RAW_BUFFER 512
bool FifoStream::sendRAWFrames() { bool FifoStream::sendRAWFrames() {
static unsigned char buffer[RAW_BUFFER]; static unsigned char buffer[RAW_BUFFER];
int fd = open(stream_path, O_RDONLY); int fd = open(stream_path.c_str(), O_RDONLY);
if ( fd < 0 ) { if ( fd < 0 ) {
Error("Can't open %s: %s", stream_path, strerror(errno)); Error("Can't open %s: %s", stream_path.c_str(), strerror(errno));
return false; return false;
} }
while ( (bytes_read = read(fd, buffer, RAW_BUFFER)) ) { while ( (bytes_read = read(fd, buffer, RAW_BUFFER)) ) {
@ -56,9 +56,9 @@ bool FifoStream::sendRAWFrames() {
bool FifoStream::sendMJEGFrames() { bool FifoStream::sendMJEGFrames() {
static unsigned char buffer[ZM_MAX_IMAGE_SIZE]; static unsigned char buffer[ZM_MAX_IMAGE_SIZE];
int fd = open(stream_path, O_RDONLY); int fd = open(stream_path.c_str(), O_RDONLY);
if ( fd < 0 ) { if ( fd < 0 ) {
Error("Can't open %s: %s", stream_path, strerror(errno)); Error("Can't open %s: %s", stream_path.c_str(), strerror(errno));
return false; return false;
} }
total_read = 0; total_read = 0;
@ -97,28 +97,26 @@ bool FifoStream::sendMJEGFrames() {
return true; return true;
} }
void FifoStream::setStreamStart(const char * path) { void FifoStream::setStreamStart(const std::string &path) {
stream_path = strdup(path); stream_path = path;
} }
void FifoStream::setStreamStart(int monitor_id, const char * format) { void FifoStream::setStreamStart(int monitor_id, const char *format) {
char diag_path[PATH_MAX]; std::string diag_path;
std::shared_ptr<Monitor> monitor = Monitor::Load(monitor_id, false, Monitor::QUERY); std::shared_ptr<Monitor> monitor = Monitor::Load(monitor_id, false, Monitor::QUERY);
if ( !strcmp(format, "reference") ) { if (!strcmp(format, "reference")) {
snprintf(diag_path, sizeof(diag_path), "%s/diagpipe-r-%u.jpg", diag_path = stringtf("%s/diagpipe-r-%u.jpg", staticConfig.PATH_SOCKS.c_str(), monitor->Id());
staticConfig.PATH_SOCKS.c_str(), monitor->Id());
stream_type = MJPEG; stream_type = MJPEG;
} else if ( !strcmp(format, "delta") ) { } else if (!strcmp(format, "delta")) {
snprintf(diag_path, sizeof(diag_path), "%s/diagpipe-d-%u.jpg", diag_path = stringtf("%s/diagpipe-d-%u.jpg", staticConfig.PATH_SOCKS.c_str(), monitor->Id());
staticConfig.PATH_SOCKS.c_str(), monitor->Id());
stream_type = MJPEG; stream_type = MJPEG;
} else { } else {
if ( strcmp(format, "raw") ) { if (strcmp(format, "raw")) {
Warning("Unknown or unspecified format. Defaulting to raw"); Warning("Unknown or unspecified format. Defaulting to raw");
} }
snprintf(diag_path, sizeof(diag_path), "%s/dbgpipe-%u.log",
staticConfig.PATH_SOCKS.c_str(), monitor->Id()); diag_path = stringtf("%s/dbgpipe-%u.log", staticConfig.PATH_SOCKS.c_str(), monitor->Id());
stream_type = RAW; stream_type = RAW;
} }
@ -126,46 +124,48 @@ void FifoStream::setStreamStart(int monitor_id, const char * format) {
} }
void FifoStream::runStream() { void FifoStream::runStream() {
if ( stream_type == MJPEG ) { if (stream_type == MJPEG) {
fprintf(stdout, "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n\r\n"); fprintf(stdout, "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n\r\n");
} else { } else {
fprintf(stdout, "Content-Type: text/html\r\n\r\n"); fprintf(stdout, "Content-Type: text/html\r\n\r\n");
} }
/* only 1 person can read from a fifo at a time, so use a lock */ /* only 1 person can read from a fifo at a time, so use a lock */
char lock_file[PATH_MAX]; std::string lock_file = stringtf("%s.rlock", stream_path.c_str());
snprintf(lock_file, sizeof(lock_file), "%s.rlock", stream_path);
Fifo::file_create_if_missing(lock_file, false); Fifo::file_create_if_missing(lock_file, false);
Debug(1, "Locking %s", lock_file); Debug(1, "Locking %s", lock_file.c_str());
int fd_lock = open(lock_file, O_RDONLY); int fd_lock = open(lock_file.c_str(), O_RDONLY);
if ( fd_lock < 0 ) { if (fd_lock < 0) {
Error("Can't open %s: %s", lock_file, strerror(errno)); Error("Can't open %s: %s", lock_file.c_str(), strerror(errno));
return; return;
} }
int res = flock(fd_lock, LOCK_EX | LOCK_NB); int res = flock(fd_lock, LOCK_EX | LOCK_NB);
while ( (res < 0 and errno == EAGAIN) and (! zm_terminate) ) { while ((res < 0 and errno == EAGAIN) and (!zm_terminate)) {
Warning("Flocking problem on %s: - %s", lock_file, strerror(errno)); Warning("Flocking problem on %s: - %s", lock_file.c_str(), strerror(errno));
sleep(1); sleep(1);
res = flock(fd_lock, LOCK_EX | LOCK_NB); res = flock(fd_lock, LOCK_EX | LOCK_NB);
} }
if ( res < 0 ) {
Error("Flocking problem on %d != %d %s: - %s", EAGAIN, res, lock_file, strerror(errno)); if (res < 0) {
Error("Flocking problem on %d != %d %s: - %s", EAGAIN, res, lock_file.c_str(), strerror(errno));
close(fd_lock); close(fd_lock);
return; return;
} }
while ( !zm_terminate ) { while (!zm_terminate) {
now = std::chrono::system_clock::now(); now = std::chrono::system_clock::now();
checkCommandQueue(); checkCommandQueue();
if ( stream_type == MJPEG ) { if (stream_type == MJPEG) {
if ( !sendMJEGFrames() ) if (!sendMJEGFrames())
zm_terminate = true; zm_terminate = true;
} else { } else {
if ( !sendRAWFrames() ) if (!sendRAWFrames())
zm_terminate = true; zm_terminate = true;
} }
} }
close(fd_lock); close(fd_lock);
} }

View File

@ -25,15 +25,10 @@ class Monitor;
class FifoStream : public StreamBase { class FifoStream : public StreamBase {
private: private:
char * stream_path; std::string stream_path;
int total_read; int total_read;
int bytes_read; int bytes_read;
unsigned int frame_count; unsigned int frame_count;
static void file_create_if_missing(
const char * path,
bool is_fifo,
bool delete_fake_fifo = true
);
protected: protected:
typedef enum { UNKNOWN, MJPEG, RAW } StreamType; typedef enum { UNKNOWN, MJPEG, RAW } StreamType;
@ -44,13 +39,13 @@ class FifoStream : public StreamBase {
public: public:
FifoStream() : FifoStream() :
stream_path(nullptr),
total_read(0), total_read(0),
bytes_read(0), bytes_read(0),
frame_count(0), frame_count(0),
stream_type(UNKNOWN) stream_type(UNKNOWN)
{} {}
void setStreamStart(const char * path);
void setStreamStart(const std::string &path);
void setStreamStart(int monitor_id, const char * format); void setStreamStart(int monitor_id, const char * format);
void runStream() override; void runStream() override;
}; };

View File

@ -48,20 +48,20 @@ FileCamera::FileCamera(
p_capture, p_capture,
p_record_audio) p_record_audio)
{ {
strncpy( path, p_path, sizeof(path)-1 ); path = std::string(p_path);
if ( capture ) { if (capture) {
Initialise(); Initialise();
} }
} }
FileCamera::~FileCamera() { FileCamera::~FileCamera() {
if ( capture ) { if (capture) {
Terminate(); Terminate();
} }
} }
void FileCamera::Initialise() { void FileCamera::Initialise() {
if ( !path[0] ) { if (path.empty()) {
Fatal("No path specified for file image"); Fatal("No path specified for file image");
} }
} }
@ -71,8 +71,8 @@ void FileCamera::Terminate() {
int FileCamera::PreCapture() { int FileCamera::PreCapture() {
struct stat statbuf = {}; struct stat statbuf = {};
if (stat(path, &statbuf) < 0) { if (stat(path.c_str(), &statbuf) < 0) {
Error("Can't stat %s: %s", path, strerror(errno)); Error("Can't stat %s: %s", path.c_str(), strerror(errno));
return -1; return -1;
} }
bytes += statbuf.st_size; bytes += statbuf.st_size;

View File

@ -27,26 +27,19 @@
// accessed using a single file which contains the latest jpeg data // accessed using a single file which contains the latest jpeg data
// //
class FileCamera : public Camera { class FileCamera : public Camera {
protected: public:
char path[PATH_MAX]; FileCamera(const Monitor *monitor,
const char *p_path,
public: int p_width,
FileCamera( int p_height,
const Monitor *monitor, int p_colours,
const char *p_path, int p_brightness,
int p_width, int p_contrast,
int p_height, int p_hue,
int p_colours, int p_colour,
int p_brightness, bool p_capture,
int p_contrast, bool p_record_audio);
int p_hue, ~FileCamera() override;
int p_colour,
bool p_capture,
bool p_record_audio
);
~FileCamera();
const char *Path() const { return path; }
void Initialise(); void Initialise();
void Terminate(); void Terminate();
@ -54,6 +47,11 @@ public:
int Capture(std::shared_ptr<ZMPacket> &p) override; int Capture(std::shared_ptr<ZMPacket> &p) override;
int PostCapture() override; int PostCapture() override;
int Close() override { return 0; }; int Close() override { return 0; };
const std::string &Path() const { return path; }
private:
std::string path;
}; };
#endif // ZM_FILE_CAMERA_H #endif // ZM_FILE_CAMERA_H

View File

@ -933,7 +933,7 @@ bool Image::WriteRaw(const char *filename) const {
return true; return true;
} }
bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int p_subpixelorder) { bool Image::ReadJpeg(const std::string &filename, unsigned int p_colours, unsigned int p_subpixelorder) {
unsigned int new_width, new_height, new_colours, new_subpixelorder; unsigned int new_width, new_height, new_colours, new_subpixelorder;
struct jpeg_decompress_struct *cinfo = readjpg_dcinfo; struct jpeg_decompress_struct *cinfo = readjpg_dcinfo;
@ -946,8 +946,8 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int
} }
FILE *infile; FILE *infile;
if ( (infile = fopen(filename, "rb")) == nullptr ) { if ( (infile = fopen(filename.c_str(), "rb")) == nullptr ) {
Error("Can't open %s: %s", filename, strerror(errno)); Error("Can't open %s: %s", filename.c_str(), strerror(errno));
return false; return false;
} }
@ -1060,24 +1060,24 @@ cinfo->out_color_space = JCS_RGB;
// Multiple calling formats to permit inclusion (or not) of non blocking, 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 // Note quality=zero means default
bool Image::WriteJpeg(const char *filename, int quality_override) const { bool Image::WriteJpeg(const std::string &filename, int quality_override) const {
return Image::WriteJpeg(filename, quality_override, {}, false); return Image::WriteJpeg(filename, quality_override, {}, false);
} }
bool Image::WriteJpeg(const char *filename) const { bool Image::WriteJpeg(const std::string &filename) const {
return Image::WriteJpeg(filename, 0, {}, false); return Image::WriteJpeg(filename, 0, {}, false);
} }
bool Image::WriteJpeg(const char *filename, bool on_blocking_abort) const { bool Image::WriteJpeg(const std::string &filename, bool on_blocking_abort) const {
return Image::WriteJpeg(filename, 0, {}, on_blocking_abort); return Image::WriteJpeg(filename, 0, {}, on_blocking_abort);
} }
bool Image::WriteJpeg(const char *filename, SystemTimePoint timestamp) const { bool Image::WriteJpeg(const std::string &filename, SystemTimePoint timestamp) const {
return Image::WriteJpeg(filename, 0, timestamp, false); return Image::WriteJpeg(filename, 0, timestamp, false);
} }
bool Image::WriteJpeg(const char *filename, int quality_override, SystemTimePoint timestamp) const { bool Image::WriteJpeg(const std::string &filename, int quality_override, SystemTimePoint timestamp) const {
return Image::WriteJpeg(filename, quality_override, timestamp, false); return Image::WriteJpeg(filename, quality_override, timestamp, false);
} }
bool Image::WriteJpeg(const char *filename, bool Image::WriteJpeg(const std::string &filename,
int quality_override, int quality_override,
SystemTimePoint timestamp, SystemTimePoint timestamp,
bool on_blocking_abort) const { bool on_blocking_abort) const {
@ -1114,17 +1114,17 @@ bool Image::WriteJpeg(const char *filename,
} }
} }
if ( !on_blocking_abort ) { if (!on_blocking_abort) {
if ( (outfile = fopen(filename, "wb")) == nullptr ) { if ((outfile = fopen(filename.c_str(), "wb")) == nullptr) {
Error("Can't open %s for writing: %s", filename, strerror(errno)); Error("Can't open %s for writing: %s", filename.c_str(), strerror(errno));
return false; return false;
} }
} else { } else {
raw_fd = open(filename, O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); raw_fd = open(filename.c_str(), O_WRONLY | O_NONBLOCK | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if ( raw_fd < 0 ) if (raw_fd < 0)
return false; return false;
outfile = fdopen(raw_fd, "wb"); outfile = fdopen(raw_fd, "wb");
if ( outfile == nullptr ) { if (outfile == nullptr) {
close(raw_fd); close(raw_fd);
return false; return false;
} }

View File

@ -233,14 +233,17 @@ class Image {
bool ReadRaw(const char *filename); bool ReadRaw(const char *filename);
bool WriteRaw(const char *filename) const; bool WriteRaw(const char *filename) const;
bool ReadJpeg(const char *filename, unsigned int p_colours, unsigned int p_subpixelorder); bool ReadJpeg(const std::string &filename, unsigned int p_colours, unsigned int p_subpixelorder);
bool WriteJpeg(const char *filename) const; bool WriteJpeg(const std::string &filename) const;
bool WriteJpeg(const char *filename, bool on_blocking_abort) const; bool WriteJpeg(const std::string &filename, bool on_blocking_abort) const;
bool WriteJpeg(const char *filename, int quality_override) const; bool WriteJpeg(const std::string &filename, int quality_override) const;
bool WriteJpeg(const char *filename, SystemTimePoint timestamp) const; bool WriteJpeg(const std::string &filename, SystemTimePoint timestamp) const;
bool WriteJpeg(const char *filename, int quality_override, SystemTimePoint timestamp) const; bool WriteJpeg(const std::string &filename, int quality_override, SystemTimePoint timestamp) const;
bool WriteJpeg(const char *filename, int quality_override, SystemTimePoint timestamp, bool on_blocking_abort) const; bool WriteJpeg(const std::string &filename,
int quality_override,
SystemTimePoint timestamp,
bool on_blocking_abort) const;
bool DecodeJpeg(const JOCTET *inbuffer, int inbuffer_size, unsigned int p_colours, unsigned int p_subpixelorder); 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; bool EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_override=0) const;

View File

@ -37,13 +37,13 @@ void zm_jpeg_emit_silence(j_common_ptr cinfo, int msg_level) {
} }
void zm_jpeg_error_exit(j_common_ptr cinfo) { void zm_jpeg_error_exit(j_common_ptr cinfo) {
static char buffer[JMSG_LENGTH_MAX]; zm_error_ptr zmerr = (zm_error_ptr) cinfo->err;
zm_error_ptr zmerr = (zm_error_ptr)cinfo->err;
(zmerr->pub.format_message)(cinfo, buffer); char buffer[JMSG_LENGTH_MAX];
zmerr->pub.format_message(cinfo, buffer);
Error("%s", buffer); Error("%s", buffer);
if ( ++jpeg_err_count == MAX_JPEG_ERRS ) { if (++jpeg_err_count == MAX_JPEG_ERRS) {
Fatal("Maximum number (%d) of JPEG errors reached, exiting", jpeg_err_count); Fatal("Maximum number (%d) of JPEG errors reached, exiting", jpeg_err_count);
} }
@ -51,25 +51,25 @@ void zm_jpeg_error_exit(j_common_ptr cinfo) {
} }
void zm_jpeg_emit_message(j_common_ptr cinfo, int msg_level) { void zm_jpeg_emit_message(j_common_ptr cinfo, int msg_level) {
static char buffer[JMSG_LENGTH_MAX]; char buffer[JMSG_LENGTH_MAX];
zm_error_ptr zmerr = (zm_error_ptr)cinfo->err; zm_error_ptr zmerr = (zm_error_ptr) cinfo->err;
if ( msg_level < 0 ) { if (msg_level < 0) {
/* It's a warning message. Since corrupt files may generate many warnings, /* It's a warning message. Since corrupt files may generate many warnings,
* the policy implemented here is to show only the first warning, * the policy implemented here is to show only the first warning,
* unless trace_level >= 3. * unless trace_level >= 3.
*/ */
if ( zmerr->pub.num_warnings == 0 || zmerr->pub.trace_level >= 3 ) { if (zmerr->pub.num_warnings == 0 || zmerr->pub.trace_level >= 3) {
(zmerr->pub.format_message)(cinfo, buffer); zmerr->pub.format_message(cinfo, buffer);
if ( !strstr(buffer, "Corrupt JPEG data:") ) if (!strstr(buffer, "Corrupt JPEG data:"))
Warning("%s", buffer); Warning("%s", buffer);
} }
/* Always count warnings in num_warnings. */ /* Always count warnings in num_warnings. */
zmerr->pub.num_warnings++; zmerr->pub.num_warnings++;
} else { } else {
/* It's a trace message. Show it if trace_level >= msg_level. */ /* It's a trace message. Show it if trace_level >= msg_level. */
if ( zmerr->pub.trace_level >= msg_level ) { if (zmerr->pub.trace_level >= msg_level) {
(zmerr->pub.format_message)(cinfo, buffer); zmerr->pub.format_message(cinfo, buffer);
Debug(msg_level, "%s", buffer); Debug(msg_level, "%s", buffer);
} }
} }

View File

@ -864,53 +864,56 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
(test) ? (prefix yesString " " capability "\n") : (prefix noString " " capability "\n") (test) ? (prefix yesString " " capability "\n") : (prefix noString " " capability "\n")
bool LocalCamera::GetCurrentSettings( bool LocalCamera::GetCurrentSettings(
const char *device, const std::string& device,
char *output, char *output,
int version, int version,
bool verbose) { bool verbose) {
output[0] = 0; output[0] = 0;
char *output_ptr = output; char *output_ptr = output;
char queryDevice[PATH_MAX] = ""; std::string queryDevice;
int devIndex = 0; int devIndex = 0;
do { do {
if ( device ) { if (!device.empty()) {
strncpy(queryDevice, device, sizeof(queryDevice)-1); queryDevice = device;
} else { } else {
sprintf(queryDevice, "/dev/video%d", devIndex); queryDevice = stringtf("/dev/video%d", devIndex);
} }
if ( (vid_fd = open(queryDevice, O_RDWR)) <= 0 ) { if ((vid_fd = open(queryDevice.c_str(), O_RDWR)) <= 0) {
if ( device ) { if (!device.empty()) {
Error("Failed to open video device %s: %s", queryDevice, strerror(errno)); Error("Failed to open video device %s: %s", queryDevice.c_str(), strerror(errno));
if ( verbose ) if (verbose) {
output_ptr += sprintf(output_ptr, "Error, failed to open video device %s: %s\n", output_ptr += sprintf(output_ptr, "Error, failed to open video device %s: %s\n",
queryDevice, strerror(errno)); queryDevice.c_str(), strerror(errno));
else } else {
output_ptr += sprintf(output_ptr, "error%d\n", errno); output_ptr += sprintf(output_ptr, "error%d\n", errno);
}
return false; return false;
} else { } else {
return true; return true;
} }
} }
if ( verbose ) {
output_ptr += sprintf(output_ptr, "Video Device: %s\n", queryDevice); if (verbose) {
output_ptr += sprintf(output_ptr, "Video Device: %s\n", queryDevice.c_str());
} else { } else {
output_ptr += sprintf(output_ptr, "d:%s|", queryDevice); output_ptr += sprintf(output_ptr, "d:%s|", queryDevice.c_str());
} }
if ( version == 2 ) { if (version == 2) {
struct v4l2_capability vid_cap; v4l2_capability vid_cap = {};
if ( vidioctl(vid_fd, VIDIOC_QUERYCAP, &vid_cap) < 0 ) { if (vidioctl(vid_fd, VIDIOC_QUERYCAP, &vid_cap) < 0) {
Error("Failed to query video device: %s", strerror(errno)); Error("Failed to query video device: %s", strerror(errno));
if ( verbose ) { if (verbose) {
output_ptr += sprintf(output_ptr, "Error, failed to query video capabilities %s: %s\n", output_ptr += sprintf(output_ptr, "Error, failed to query video capabilities %s: %s\n",
queryDevice, strerror(errno)); queryDevice.c_str(), strerror(errno));
} else { } else {
output_ptr += sprintf(output_ptr, "error%d\n", errno); output_ptr += sprintf(output_ptr, "error%d\n", errno);
} }
if ( device ) if (!device.empty()) {
return false; return false;
}
} }
if ( verbose ) { if ( verbose ) {
@ -953,7 +956,7 @@ bool LocalCamera::GetCurrentSettings(
output_ptr += sprintf(output_ptr, verbose ? " Standards:\n" : "S:"); output_ptr += sprintf(output_ptr, verbose ? " Standards:\n" : "S:");
struct v4l2_standard standard; v4l2_standard standard = {};
int standardIndex = 0; int standardIndex = 0;
do { do {
memset(&standard, 0, sizeof(standard)); memset(&standard, 0, sizeof(standard));
@ -981,10 +984,10 @@ bool LocalCamera::GetCurrentSettings(
*(output_ptr-1) = '|'; *(output_ptr-1) = '|';
output_ptr += sprintf(output_ptr, verbose ? " Formats:\n" : "F:"); output_ptr += sprintf(output_ptr, verbose ? " Formats:\n" : "F:");
struct v4l2_fmtdesc format;
int formatIndex = 0; int formatIndex = 0;
do { do {
memset(&format, 0, sizeof(format)); v4l2_fmtdesc format = {};
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.index = formatIndex; format.index = formatIndex;
@ -1025,9 +1028,9 @@ bool LocalCamera::GetCurrentSettings(
else else
output_ptr += sprintf(output_ptr, "Crop Capabilities\n"); output_ptr += sprintf(output_ptr, "Crop Capabilities\n");
struct v4l2_cropcap cropcap; v4l2_cropcap cropcap = {};
memset(&cropcap, 0, sizeof(cropcap));
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( vidioctl(vid_fd, VIDIOC_CROPCAP, &cropcap) < 0 ) { if ( vidioctl(vid_fd, VIDIOC_CROPCAP, &cropcap) < 0 ) {
if ( errno != EINVAL ) { if ( errno != EINVAL ) {
/* Failed querying crop capability, write error to the log and continue as if crop is not supported */ /* Failed querying crop capability, write error to the log and continue as if crop is not supported */
@ -1041,8 +1044,8 @@ bool LocalCamera::GetCurrentSettings(
output_ptr += sprintf(output_ptr, "B:%dx%d|", 0, 0); output_ptr += sprintf(output_ptr, "B:%dx%d|", 0, 0);
} }
} else { } else {
struct v4l2_crop crop; v4l2_crop crop = {};
memset(&crop, 0, sizeof(crop));
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( vidioctl(vid_fd, VIDIOC_G_CROP, &crop) < 0 ) { if ( vidioctl(vid_fd, VIDIOC_G_CROP, &crop) < 0 ) {
@ -1159,8 +1162,9 @@ bool LocalCamera::GetCurrentSettings(
} }
close(vid_fd); close(vid_fd);
if ( device ) if (!device.empty()) {
break; break;
}
} while ( ++devIndex < 32 ); } while ( ++devIndex < 32 );
return true; return true;
} }

View File

@ -123,7 +123,7 @@ public:
int Capture(std::shared_ptr<ZMPacket> &p) override; int Capture(std::shared_ptr<ZMPacket> &p) override;
int PostCapture() override; int PostCapture() override;
int Close() override; int Close() override;
static bool GetCurrentSettings(const char *device, char *output, int version, bool verbose); static bool GetCurrentSettings(const std::string &device, char *output, int version, bool verbose);
}; };
#endif // ZM_HAS_V4L #endif // ZM_HAS_V4L

View File

@ -524,8 +524,8 @@ void Logger::logPrint(bool hex, const char *filepath, int line, int level, const
"INSERT INTO `Logs` " "INSERT INTO `Logs` "
"( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )" "( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )"
" VALUES " " VALUES "
"( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", "( %ld.%06" PRIi64 ", '%s', %d, %d, %d, '%s', '%s', '%s', %d )",
now_sec, now_frac.count(), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, now_sec, static_cast<int64>(now_frac.count()), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString,
escapedString.c_str(), file, line); escapedString.c_str(), file, line);
dbQueue.push(std::move(sql_string)); dbQueue.push(std::move(sql_string));
} else { } else {

View File

@ -1184,8 +1184,7 @@ int Monitor::GetImage(int32_t index, int scale) {
image = image_buffer[index]; image = image_buffer[index];
} }
static char filename[PATH_MAX]; std::string filename = stringtf("Monitor%u.jpg", id);
snprintf(filename, sizeof(filename), "Monitor%u.jpg", id);
image->WriteJpeg(filename); image->WriteJpeg(filename);
return 1; return 1;
} }
@ -1506,20 +1505,20 @@ void Monitor::DumpZoneImage(const char *zone_string) {
zone_image->Outline(extra_colour, extra_zone); zone_image->Outline(extra_colour, extra_zone);
} }
static char filename[PATH_MAX]; std::string filename = stringtf("Zones%u.jpg", id);
snprintf(filename, sizeof(filename), "Zones%u.jpg", id);
zone_image->WriteJpeg(filename); zone_image->WriteJpeg(filename);
delete zone_image; delete zone_image;
} // end void Monitor::DumpZoneImage(const char *zone_string) } // end void Monitor::DumpZoneImage(const char *zone_string)
void Monitor::DumpImage(Image *dump_image) const { void Monitor::DumpImage(Image *dump_image) const {
if ( image_count && !(image_count%10) ) { if (image_count && !(image_count % 10)) {
static char filename[PATH_MAX];
static char new_filename[PATH_MAX]; std::string filename = stringtf("Monitor%u.jpg", id);
snprintf(filename, sizeof(filename), "Monitor%u.jpg", id); std::string new_filename = stringtf("Monitor%u-new.jpg", id);
snprintf(new_filename, sizeof(new_filename), "Monitor%u-new.jpg", id);
if ( dump_image->WriteJpeg(new_filename) ) if (dump_image->WriteJpeg(new_filename)) {
rename(new_filename, filename); rename(new_filename.c_str(), filename.c_str());
}
} }
} // end void Monitor::DumpImage(Image *dump_image) } // end void Monitor::DumpImage(Image *dump_image)
@ -2783,8 +2782,8 @@ unsigned int Monitor::DetectMotion(const Image &comp_image, Event::StringSet &zo
ref_image.Delta(comp_image, &delta_image); ref_image.Delta(comp_image, &delta_image);
if (config.record_diag_images) { if (config.record_diag_images) {
ref_image.WriteJpeg(diag_path_ref.c_str(), config.record_diag_images_fifo); ref_image.WriteJpeg(diag_path_ref, config.record_diag_images_fifo);
delta_image.WriteJpeg(diag_path_delta.c_str(), config.record_diag_images_fifo); delta_image.WriteJpeg(diag_path_delta, config.record_diag_images_fifo);
} }
// Blank out all exclusion zones // Blank out all exclusion zones
@ -2932,7 +2931,7 @@ bool Monitor::DumpSettings(char *output, bool verbose) {
sprintf( output+strlen(output), "Path : %s\n", cam->Path().c_str() ); sprintf( output+strlen(output), "Path : %s\n", cam->Path().c_str() );
} else if ( camera->IsFile() ) { } else if ( camera->IsFile() ) {
FileCamera* cam = static_cast<FileCamera*>(camera.get()); FileCamera* cam = static_cast<FileCamera*>(camera.get());
sprintf( output+strlen(output), "Path : %s\n", cam->Path() ); sprintf( output+strlen(output), "Path : %s\n", cam->Path().c_str() );
} }
else if ( camera->IsFfmpeg() ) { else if ( camera->IsFfmpeg() ) {
FfmpegCamera* cam = static_cast<FfmpegCamera*>(camera.get()); FfmpegCamera* cam = static_cast<FfmpegCamera*>(camera.get());

View File

@ -320,7 +320,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
//updateFrameRate(monitor->GetFPS()); //updateFrameRate(monitor->GetFPS());
} // end void MonitorStream::processCommand(const CmdMsg *msg) } // end void MonitorStream::processCommand(const CmdMsg *msg)
bool MonitorStream::sendFrame(const char *filepath, SystemTimePoint timestamp) { bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint timestamp) {
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE));
if ( if (
@ -330,19 +330,18 @@ bool MonitorStream::sendFrame(const char *filepath, SystemTimePoint timestamp) {
) )
send_raw = false; send_raw = false;
if ( !send_raw ) { if (!send_raw) {
Image temp_image(filepath); Image temp_image(filepath.c_str());
return sendFrame(&temp_image, timestamp); return sendFrame(&temp_image, timestamp);
} else { } else {
int img_buffer_size = 0; int img_buffer_size = 0;
static unsigned char img_buffer[ZM_MAX_IMAGE_SIZE]; static unsigned char img_buffer[ZM_MAX_IMAGE_SIZE];
FILE *fdj = nullptr; if (FILE *fdj = fopen(filepath.c_str(), "r")) {
if ( (fdj = fopen(filepath, "r")) ) {
img_buffer_size = fread(img_buffer, 1, sizeof(img_buffer), fdj); img_buffer_size = fread(img_buffer, 1, sizeof(img_buffer), fdj);
fclose(fdj); fclose(fdj);
} else { } else {
Error("Can't open %s: %s", filepath, strerror(errno)); Error("Can't open %s: %s", filepath.c_str(), strerror(errno));
return false; return false;
} }
@ -747,21 +746,13 @@ void MonitorStream::runStream() {
int temp_index = temp_write_index%temp_image_buffer_count; int temp_index = temp_write_index%temp_image_buffer_count;
Debug(2, "Storing frame %d", temp_index); Debug(2, "Storing frame %d", temp_index);
if ( !temp_image_buffer[temp_index].valid ) { if ( !temp_image_buffer[temp_index].valid ) {
snprintf( temp_image_buffer[temp_index].file_name = stringtf("%s/zmswap-i%05d.jpg", swap_path.c_str(), temp_index);
temp_image_buffer[temp_index].file_name,
sizeof(temp_image_buffer[0].file_name),
"%s/zmswap-i%05d.jpg",
swap_path.c_str(),
temp_index);
temp_image_buffer[temp_index].valid = true; temp_image_buffer[temp_index].valid = true;
} }
temp_image_buffer[temp_index].timestamp = temp_image_buffer[temp_index].timestamp =
SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index])); SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index]));
monitor->image_buffer[index]->WriteJpeg( monitor->image_buffer[index]->WriteJpeg(temp_image_buffer[temp_index].file_name, config.jpeg_file_quality);
temp_image_buffer[temp_index].file_name,
config.jpeg_file_quality
);
temp_write_index = MOD_ADD(temp_write_index, 1, temp_image_buffer_count); temp_write_index = MOD_ADD(temp_write_index, 1, temp_image_buffer_count);
if ( temp_write_index == temp_read_index ) { if ( temp_write_index == temp_read_index ) {
// Go back to live viewing // Go back to live viewing
@ -812,7 +803,7 @@ void MonitorStream::runStream() {
if ( buffered_playback ) { if ( buffered_playback ) {
Debug(1, "Cleaning swap files from %s", swap_path.c_str()); Debug(1, "Cleaning swap files from %s", swap_path.c_str());
struct stat stat_buf; struct stat stat_buf = {};
if ( stat(swap_path.c_str(), &stat_buf) < 0 ) { if ( stat(swap_path.c_str(), &stat_buf) < 0 ) {
if ( errno != ENOENT ) { if ( errno != ENOENT ) {
Error("Can't stat '%s': %s", swap_path.c_str(), strerror(errno)); Error("Can't stat '%s': %s", swap_path.c_str(), strerror(errno));
@ -820,16 +811,15 @@ void MonitorStream::runStream() {
} else if ( !S_ISDIR(stat_buf.st_mode) ) { } else if ( !S_ISDIR(stat_buf.st_mode) ) {
Error("Swap image path '%s' is not a directory", swap_path.c_str()); Error("Swap image path '%s' is not a directory", swap_path.c_str());
} else { } else {
char glob_pattern[PATH_MAX] = ""; std::string glob_pattern = stringtf("%s/*.*", swap_path.c_str());
snprintf(glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path.c_str());
glob_t pglob; glob_t pglob;
int glob_status = glob(glob_pattern, 0, 0, &pglob);
int glob_status = glob(glob_pattern.c_str(), 0, 0, &pglob);
if ( glob_status != 0 ) { if ( glob_status != 0 ) {
if ( glob_status < 0 ) { if ( glob_status < 0 ) {
Error("Can't glob '%s': %s", glob_pattern, strerror(errno)); Error("Can't glob '%s': %s", glob_pattern.c_str(), strerror(errno));
} else { } else {
Debug(1, "Can't glob '%s': %d", glob_pattern, glob_status); Debug(1, "Can't glob '%s': %d", glob_pattern.c_str(), glob_status);
} }
} else { } else {
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) { for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) {

View File

@ -27,7 +27,7 @@ class MonitorStream : public StreamBase {
struct SwapImage { struct SwapImage {
bool valid = false; bool valid = false;
SystemTimePoint timestamp; SystemTimePoint timestamp;
char file_name[PATH_MAX] = ""; std::string file_name;
}; };
private: private:
@ -44,7 +44,7 @@ class MonitorStream : public StreamBase {
protected: protected:
bool checkSwapPath(const char *path, bool create_path); bool checkSwapPath(const char *path, bool create_path);
bool sendFrame(const char *filepath, SystemTimePoint timestamp); bool sendFrame(const std::string &filepath, SystemTimePoint timestamp);
bool sendFrame(Image *image, SystemTimePoint timestamp); bool sendFrame(Image *image, SystemTimePoint timestamp);
void processCommand(const CmdMsg *msg) override; void processCommand(const CmdMsg *msg) override;
void SingleImage(int scale=100); void SingleImage(int scale=100);

View File

@ -22,6 +22,7 @@
#include "zm_config.h" #include "zm_config.h"
#include "zm_logger.h" #include "zm_logger.h"
#include <array> #include <array>
#include <cstdarg>
#include <cstring> #include <cstring>
#include <fcntl.h> /* Definition of AT_* constants */ #include <fcntl.h> /* Definition of AT_* constants */
#include <sstream> #include <sstream>
@ -116,6 +117,26 @@ std::string Join(const StringVector &values, const std::string &delim) {
return ss.str(); return ss.str();
} }
std::string stringtf(const char* format, ...) {
va_list args;
va_start(args, format);
va_list args2;
va_copy(args2, args);
int size = vsnprintf(nullptr, 0, format, args) + 1; // Extra space for '\0'
va_end(args);
if (size <= 0) {
throw std::runtime_error("Error during formatting.");
}
std::unique_ptr<char[]> buf(new char[size]);
vsnprintf(buf.get(), size, format, args2);
va_end(args2);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
std::string ByteArrayToHexString(nonstd::span<const uint8> bytes) { std::string ByteArrayToHexString(nonstd::span<const uint8> bytes) {
static constexpr char lowercase_table[] = "0123456789abcdef"; static constexpr char lowercase_table[] = "0123456789abcdef";
std::string buf; std::string buf;

View File

@ -61,16 +61,8 @@ inline bool StartsWith(const std::string &haystack, const std::string &needle) {
return (haystack.substr(0, needle.length()) == needle); return (haystack.substr(0, needle.length()) == needle);
} }
template<typename... Args> __attribute__((format(printf, 1, 2)))
std::string stringtf(const std::string &format, Args... args) { std::string stringtf(const char* format, ...);
int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
if (size <= 0) {
throw std::runtime_error("Error during formatting.");
}
std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
std::string ByteArrayToHexString(nonstd::span<const uint8> bytes); std::string ByteArrayToHexString(nonstd::span<const uint8> bytes);

View File

@ -104,7 +104,8 @@ void Zone::Setup(
diag_path = stringtf("%s/diag-%d-poly.jpg", diag_path = stringtf("%s/diag-%d-poly.jpg",
monitor->getStorage()->Path(), id); monitor->getStorage()->Path(), id);
} }
pg_image->WriteJpeg(diag_path.c_str(), config.record_diag_images_fifo);
pg_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
} }
} // end Zone::Setup } // end Zone::Setup
@ -232,8 +233,9 @@ bool Zone::CheckAlarms(const Image *delta_image) {
} */ } */
std_alarmedpixels(diff_image, pg_image, &stats.alarm_pixels_, &pixel_diff_count); std_alarmedpixels(diff_image, pg_image, &stats.alarm_pixels_, &pixel_diff_count);
if (config.record_diag_images) if (config.record_diag_images) {
diff_image->WriteJpeg(diag_path.c_str(), config.record_diag_images_fifo); diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
}
if (pixel_diff_count && stats.alarm_pixels_) if (pixel_diff_count && stats.alarm_pixels_)
stats.pixel_diff_ = pixel_diff_count/stats.alarm_pixels_; stats.pixel_diff_ = pixel_diff_count/stats.alarm_pixels_;
@ -316,8 +318,9 @@ bool Zone::CheckAlarms(const Image *delta_image) {
stats.alarm_filter_pixels_ = stats.alarm_pixels_; stats.alarm_filter_pixels_ = stats.alarm_pixels_;
} }
if (config.record_diag_images) if (config.record_diag_images) {
diff_image->WriteJpeg(diag_path.c_str(), config.record_diag_images_fifo); diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
}
Debug(5, "Got %d filtered pixels, need %d -> %d", Debug(5, "Got %d filtered pixels, need %d -> %d",
stats.alarm_filter_pixels_, min_filter_pixels, max_filter_pixels); stats.alarm_filter_pixels_, min_filter_pixels, max_filter_pixels);
@ -540,8 +543,9 @@ bool Zone::CheckAlarms(const Image *delta_image) {
} }
} }
if (config.record_diag_images) if (config.record_diag_images) {
diff_image->WriteJpeg(diag_path.c_str(), config.record_diag_images_fifo); diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
}
if (!stats.alarm_blobs_) { if (!stats.alarm_blobs_) {
stats.score_ = 0; stats.score_ = 0;
@ -592,8 +596,9 @@ bool Zone::CheckAlarms(const Image *delta_image) {
} // end if bs_count } // end if bs_count
} // end for i < WHITE } // end for i < WHITE
if (config.record_diag_images) if (config.record_diag_images) {
diff_image->WriteJpeg(diag_path.c_str(), config.record_diag_images_fifo); diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
}
Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d",
stats.alarm_blob_pixels_, stats.alarm_blobs_, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); stats.alarm_blob_pixels_, stats.alarm_blobs_, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs);