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:
commit
b0cf3a4732
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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,14 +129,13 @@ 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 const char *getSubPath(time_t *time) {
|
static std::string 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);
|
||||||
|
|
|
@ -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,45 +180,42 @@ 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 {
|
||||||
snprintf(event_data->path, sizeof(event_data->path),
|
event_data->path = stringtf("%s/%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||||
"%s/%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
|
|
||||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
staticConfig.PATH_WEB.c_str(), 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 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
|
|
||||||
snprintf(event_data->path, sizeof(event_data->path),
|
|
||||||
"%s/%s/%u/%04d-%02d-%02d/%" PRIu64,
|
|
||||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_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] == '/' )
|
event_data->path = stringtf("%s/%s/%u/%04d-%02d-%02d/%" PRIu64,
|
||||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%u/%" PRIu64,
|
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||||
storage_path, event_data->monitor_id, event_data->event_id);
|
event_time.tm_year + 1900, event_time.tm_mon + 1, event_time.tm_mday,
|
||||||
else
|
event_data->event_id);
|
||||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%u/%" PRIu64,
|
}
|
||||||
|
} else {
|
||||||
|
if (storage_path[0] == '/') {
|
||||||
|
event_data->path = stringtf("%s/%u/%" PRIu64, storage_path, event_data->monitor_id, event_data->event_id);
|
||||||
|
} else {
|
||||||
|
event_data->path = stringtf("%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;
|
||||||
if ((event_data->frame_count and event_data->duration != Seconds(0))) {
|
if ((event_data->frame_count and event_data->duration != Seconds(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) ) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -27,12 +27,8 @@
|
||||||
// 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,
|
||||||
|
|
||||||
public:
|
|
||||||
FileCamera(
|
|
||||||
const Monitor *monitor,
|
|
||||||
const char *p_path,
|
const char *p_path,
|
||||||
int p_width,
|
int p_width,
|
||||||
int p_height,
|
int p_height,
|
||||||
|
@ -42,11 +38,8 @@ public:
|
||||||
int p_hue,
|
int p_hue,
|
||||||
int p_colour,
|
int p_colour,
|
||||||
bool p_capture,
|
bool p_capture,
|
||||||
bool p_record_audio
|
bool p_record_audio);
|
||||||
);
|
~FileCamera() override;
|
||||||
~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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -864,54 +864,57 @@ 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 ) {
|
||||||
output_ptr += sprintf(output_ptr, "General Capabilities\n"
|
output_ptr += sprintf(output_ptr, "General Capabilities\n"
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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++ ) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue