v1.6.t8
going back to basics. removed all threading code and opted for a multi process architecture using fork(). previous code had a bad memory leak and doesn't handle unexpected camera disconnects and for some reason it also didn't recover gracefully in systemctl when it crashes. Hopefully this new re-write fixes all of those numerous issues. moDetect() will now try multiple times to grab buffer footage before giving up and moving on.
This commit is contained in:
parent
4dcd6c05a3
commit
13eaf75c8a
|
@ -355,13 +355,3 @@ string parseForParam(const string &arg, int argc, char** argv, bool argOnly)
|
|||
|
||||
return parseForParam(arg, argc, argv, argOnly, notUsed);
|
||||
}
|
||||
|
||||
void waitForDetThreads(shared_t *share)
|
||||
{
|
||||
for (auto &&thr : share->detThreads)
|
||||
{
|
||||
thr.join();
|
||||
}
|
||||
|
||||
share->detThreads.clear();
|
||||
}
|
||||
|
|
86
src/common.h
86
src/common.h
|
@ -21,8 +21,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <pthread.h>
|
||||
#include <filesystem>
|
||||
#include <mutex>
|
||||
#include <sys/types.h>
|
||||
|
@ -37,53 +35,47 @@ using namespace cv;
|
|||
using namespace std;
|
||||
using namespace std::filesystem;
|
||||
|
||||
#define APP_VER "1.6.t7"
|
||||
#define APP_NAME "Motion Watch"
|
||||
#define TRIM_REMOVE " \n\r\t\f\v."
|
||||
#define APP_VER "1.6.t8"
|
||||
#define APP_NAME "Motion Watch"
|
||||
#define TRIM_REMOVE " \n\r\t\f\v."
|
||||
#define PATH_ADDR 9
|
||||
#define MAX_CAP_RETRY 3
|
||||
|
||||
struct shared_t
|
||||
{
|
||||
vector<thread> detThreads;
|
||||
ofstream recLogFile;
|
||||
ofstream detLogFile;
|
||||
string conf;
|
||||
string recLogPath;
|
||||
string detLogPath;
|
||||
string recordUrl;
|
||||
string detectUrl;
|
||||
string outDir;
|
||||
string postCmd;
|
||||
string buffDir;
|
||||
string recSuffix;
|
||||
string detSuffix;
|
||||
string vidExt;
|
||||
string vidCodec;
|
||||
string camName;
|
||||
string webBg;
|
||||
string webTxt;
|
||||
string webFont;
|
||||
string webRoot;
|
||||
bool init;
|
||||
bool skipCmd;
|
||||
bool updateRoot;
|
||||
int cmdFinished;
|
||||
int clipLen;
|
||||
int frameGap;
|
||||
int pixThresh;
|
||||
int imgThresh;
|
||||
int numOfClips;
|
||||
int maxDays;
|
||||
int maxClips;
|
||||
int maxLogSize;
|
||||
int retCode;
|
||||
};
|
||||
|
||||
struct cmdRes_t
|
||||
{
|
||||
string cmd;
|
||||
pthread_t thr;
|
||||
int ret;
|
||||
bool finished;
|
||||
ofstream recLogFile;
|
||||
ofstream detLogFile;
|
||||
string conf;
|
||||
string recLogPath;
|
||||
string detLogPath;
|
||||
string recordUrl;
|
||||
string detectUrl;
|
||||
string outDir;
|
||||
string postCmd;
|
||||
string buffDir;
|
||||
string recSuffix;
|
||||
string detSuffix;
|
||||
string vidExt;
|
||||
string vidCodec;
|
||||
string camName;
|
||||
string webBg;
|
||||
string webTxt;
|
||||
string webFont;
|
||||
string webRoot;
|
||||
bool init;
|
||||
bool skipCmd;
|
||||
bool updateRoot;
|
||||
int detProcs;
|
||||
int clipLen;
|
||||
int frameGap;
|
||||
int pixThresh;
|
||||
int imgThresh;
|
||||
int numOfClips;
|
||||
int maxDays;
|
||||
int maxClips;
|
||||
int maxLogSize;
|
||||
int index;
|
||||
int retCode;
|
||||
};
|
||||
|
||||
string leftTrim(const string &str, const string &toRemove);
|
||||
|
@ -101,8 +93,6 @@ void enforceMaxDays(const string &dirPath, shared_t *share);
|
|||
void enforceMaxClips(const string &dirPath, shared_t *share);
|
||||
void rdLine(const string ¶m, const string &line, string *value);
|
||||
void rdLine(const string ¶m, const string &line, int *value);
|
||||
void statOut(shared_t *share);
|
||||
void waitForDetThreads(shared_t *share);
|
||||
bool rdConf(shared_t *share);
|
||||
vector<string> lsFilesInDir(const string &path, const string &ext = string());
|
||||
vector<string> lsDirsInDir(const string &path);
|
||||
|
|
201
src/main.cpp
201
src/main.cpp
|
@ -15,127 +15,40 @@
|
|||
|
||||
void detectMoInFile(const string &detPath, const string &recPath, shared_t *share)
|
||||
{
|
||||
detLog("detect_mo_in_file() -- start", share);
|
||||
|
||||
Mat thumbNail;
|
||||
|
||||
if (moDetect(detPath, thumbNail, share))
|
||||
if (fork() == 0)
|
||||
{
|
||||
share->skipCmd = true;
|
||||
detLog("detect_mo_in_file() -- start", share);
|
||||
|
||||
wrOut(recPath, thumbNail, share);
|
||||
}
|
||||
share->detProcs++;
|
||||
|
||||
if (exists(detPath)) remove(detPath);
|
||||
if (exists(recPath)) remove(recPath);
|
||||
|
||||
detLog("detect_mo_in_file() -- finished", share);
|
||||
}
|
||||
|
||||
static void *runCmd(void *arg)
|
||||
{
|
||||
auto args = static_cast<cmdRes_t*>(arg);
|
||||
|
||||
args->finished = false;
|
||||
args->ret = 0;
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
|
||||
args->ret = pclose(popen(args->cmd.c_str(), "r"));
|
||||
args->finished = true;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool allCmdsFinished(const vector<cmdRes_t*> &resList)
|
||||
{
|
||||
for (auto &&res : resList)
|
||||
{
|
||||
if (!res->finished) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cancelAllCmds(const vector<cmdRes_t*> &resList)
|
||||
{
|
||||
for (auto &&res : resList)
|
||||
{
|
||||
if (!res->finished)
|
||||
if (exists(detPath))
|
||||
{
|
||||
pthread_cancel(res->thr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Mat thumbNail;
|
||||
|
||||
bool allCmdsDidNotFail(const vector<cmdRes_t*> &resList)
|
||||
{
|
||||
for (auto &&res : resList)
|
||||
{
|
||||
if (res->ret != 0) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleanupRes(vector<cmdRes_t*> &resList)
|
||||
{
|
||||
for (auto &&res : resList)
|
||||
{
|
||||
delete res;
|
||||
}
|
||||
}
|
||||
|
||||
void runTOCmds(int timeOut, const vector<string> &cmds, vector<cmdRes_t*> &resList, bool abs = true)
|
||||
{
|
||||
resList.clear();
|
||||
|
||||
for (auto &&cmd : cmds)
|
||||
{
|
||||
auto res = new struct cmdRes_t;
|
||||
|
||||
res->cmd = cmd;
|
||||
res->finished = false;
|
||||
|
||||
pthread_create(&res->thr, NULL, &runCmd, res);
|
||||
|
||||
resList.push_back(res);
|
||||
}
|
||||
|
||||
if (abs)
|
||||
{
|
||||
sleep(timeOut);
|
||||
|
||||
if (!allCmdsFinished(resList))
|
||||
{
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
cancelAllCmds(resList);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i = 0; !allCmdsFinished(resList); ++i)
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
if (i >= timeOut)
|
||||
if (moDetect(detPath, thumbNail, share))
|
||||
{
|
||||
cancelAllCmds(resList); break;
|
||||
share->skipCmd = true;
|
||||
|
||||
wrOut(recPath, thumbNail, share);
|
||||
}
|
||||
}
|
||||
|
||||
if (exists(detPath)) remove(detPath);
|
||||
if (exists(recPath)) remove(recPath);
|
||||
|
||||
share->detProcs--;
|
||||
|
||||
detLog("detect_mo_in_file() -- finished", share);
|
||||
}
|
||||
}
|
||||
|
||||
void runTOCmd(int timeout, const string &cmd, bool abs = true)
|
||||
void exeCmd(char *const argv[])
|
||||
{
|
||||
vector<string> cmds;
|
||||
vector<cmdRes_t*> rets;
|
||||
|
||||
cmds.push_back(cmd);
|
||||
|
||||
runTOCmds(timeout, cmds, rets, abs);
|
||||
cleanupRes(rets);
|
||||
if (fork() == 0)
|
||||
{
|
||||
execvp("ffmpeg", argv);
|
||||
_Exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void recLoop(shared_t *share)
|
||||
|
@ -169,47 +82,63 @@ void recLoop(shared_t *share)
|
|||
|
||||
recLog("camera specific webroot page updated: " + share->outDir + "/index.html", share);
|
||||
|
||||
for (auto i = 0; i < share->numOfClips; ++i)
|
||||
{
|
||||
auto detPath = cleanDir(share->buffDir) + "/" + to_string(i) + share->detSuffix;
|
||||
auto recPath = cleanDir(share->buffDir) + "/" + to_string(i) + share->recSuffix;
|
||||
auto strClipLen = to_string(share->clipLen);
|
||||
|
||||
vector<string> cmds;
|
||||
vector<cmdRes_t*> rets;
|
||||
char* argvRec[] = {(char*) "ffmpeg",
|
||||
(char*) "-hide_banner",
|
||||
(char*) "-i",
|
||||
(char*) share->recordUrl.c_str(),
|
||||
(char*) "-y",
|
||||
(char*) "-vcodec",
|
||||
(char*) share->vidCodec.c_str(),
|
||||
(char*) "-t",
|
||||
(char*) strClipLen.c_str(),
|
||||
(char*) "--replace_me--",
|
||||
NULL};
|
||||
|
||||
char* argvDet[] = {(char*) "ffmpeg",
|
||||
(char*) "-hide_banner",
|
||||
(char*) "-i",
|
||||
(char*) share->detectUrl.c_str(),
|
||||
(char*) "-y",
|
||||
(char*) "-vcodec",
|
||||
(char*) share->vidCodec.c_str(),
|
||||
(char*) "-t",
|
||||
(char*) strClipLen.c_str(),
|
||||
(char*) "--replace_me--",
|
||||
NULL};
|
||||
|
||||
for (auto i = 0; i < share->numOfClips; ++i, ++share->index)
|
||||
{
|
||||
auto detPath = cleanDir(share->buffDir) + "/" + to_string(share->index) + share->detSuffix;
|
||||
auto recPath = cleanDir(share->buffDir) + "/" + to_string(share->index) + share->recSuffix;
|
||||
|
||||
if (share->recordUrl == share->detectUrl)
|
||||
{
|
||||
recPath = detPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds.push_back("ffmpeg -hide_banner -i " + share->recordUrl + " -y -vcodec " + share->vidCodec + " -t " + to_string(share->clipLen) + " " + recPath);
|
||||
}
|
||||
|
||||
cmds.push_back("ffmpeg -hide_banner -i " + share->detectUrl + " -y -vcodec " + share->vidCodec + " -t " + to_string(share->clipLen) + " " + detPath);
|
||||
argvRec[PATH_ADDR] = (char*) recPath.c_str();
|
||||
argvDet[PATH_ADDR] = (char*) detPath.c_str();
|
||||
|
||||
recLog("fetching camera footage -- ", share);
|
||||
|
||||
runTOCmds(share->clipLen, cmds, rets);
|
||||
|
||||
for (auto &&ret : rets)
|
||||
if (share->recordUrl == share->detectUrl)
|
||||
{
|
||||
recLog("cmd: " + ret->cmd + " return_code: " + to_string(ret->ret), share);
|
||||
}
|
||||
|
||||
if (allCmdsDidNotFail(rets))
|
||||
{
|
||||
share->detThreads.push_back(thread(detectMoInFile, detPath, recPath, share));
|
||||
exeCmd(argvDet);
|
||||
}
|
||||
else
|
||||
{
|
||||
recLog("one or both fetch cmds failed.", share);
|
||||
exeCmd(argvDet);
|
||||
exeCmd(argvRec);
|
||||
}
|
||||
|
||||
cleanupRes(rets);
|
||||
sleep(share->clipLen * 2);
|
||||
|
||||
detectMoInFile(detPath, recPath, share);
|
||||
}
|
||||
|
||||
waitForDetThreads(share);
|
||||
while (share->detProcs > 0) sleep(1);
|
||||
|
||||
if (!share->skipCmd)
|
||||
{
|
||||
|
@ -222,7 +151,8 @@ void recLoop(shared_t *share)
|
|||
else
|
||||
{
|
||||
recLog("running post command: " + share->postCmd, share);
|
||||
runTOCmd(14, share->postCmd, false);
|
||||
|
||||
system(string("timeout -k 1 14 " + share->postCmd).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -236,6 +166,9 @@ void recLoop(shared_t *share)
|
|||
{
|
||||
break;
|
||||
}
|
||||
|
||||
destroy_at(argvDet);
|
||||
destroy_at(argvRec);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,6 +224,8 @@ int main(int argc, char** argv)
|
|||
else
|
||||
{
|
||||
sharedRes.retCode = 0;
|
||||
sharedRes.detProcs = 0;
|
||||
sharedRes.index = 0;
|
||||
sharedRes.updateRoot = true;
|
||||
sharedRes.skipCmd = false;
|
||||
sharedRes.init = true;
|
||||
|
|
|
@ -95,16 +95,31 @@ void wrOut(const string &buffFile, const Mat &vidThumb, shared_t *share)
|
|||
detLog("wr_out() -- finished()", share);
|
||||
}
|
||||
|
||||
bool openVid(const string &buffFile, VideoCapture &cap)
|
||||
{
|
||||
auto ret = cap.open(buffFile.c_str(), CAP_FFMPEG);
|
||||
|
||||
for (auto i = 0; (i < 3) && !ret; ++i)
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
ret = cap.open(buffFile.c_str(), CAP_FFMPEG);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool moDetect(const string &buffFile, Mat &vidThumb, shared_t *share)
|
||||
{
|
||||
detLog("mo_detect() -- start()", share);
|
||||
detLog("buff_file: " + buffFile, share);
|
||||
|
||||
auto mod = false;
|
||||
auto mod = false;
|
||||
auto trys = 0;
|
||||
|
||||
VideoCapture capture(buffFile.c_str(), CAP_FFMPEG);
|
||||
VideoCapture capture;
|
||||
|
||||
if (capture.isOpened())
|
||||
if (openVid(buffFile, capture))
|
||||
{
|
||||
Mat prev;
|
||||
Mat next;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "web.h"
|
||||
#include "logger.h"
|
||||
|
||||
bool openVid(const string &buffFile, VideoCapture &cap);
|
||||
bool imgDiff(const Mat &prev, const Mat &next, shared_t *share);
|
||||
bool moDetect(const string &buffFile, Mat &vidThumb, shared_t *share);
|
||||
void wrOut(const string &buffFile, const Mat &vidThumb, shared_t *share);
|
||||
|
|
Loading…
Reference in New Issue
Block a user