The app is still failing with intermittent moov atom failures on trying
to open the video clips with opencv VideoCapture. I suspect it is trying
to open the files while ffmpeg is not done finalizing them. Reformed the
detection loop to spawn dedicated motion detection threads for each
video clip and only when ffmpeg confirmed finished.
This commit is contained in:
Maurice ONeal 2022-12-21 20:30:37 -05:00
parent ad4a6357b4
commit b470915276
4 changed files with 78 additions and 95 deletions

View File

@ -202,7 +202,6 @@ bool rdConf(shared_t *share)
share->buffDir = "/tmp"; share->buffDir = "/tmp";
share->vidExt = "mp4"; share->vidExt = "mp4";
share->vidCodec = "copy"; share->vidCodec = "copy";
share->recLoopWait = false;
share->skipCmd = false; share->skipCmd = false;
share->webBg = "#485564"; share->webBg = "#485564";
share->webTxt = "#dee5ee"; share->webTxt = "#dee5ee";
@ -284,3 +283,13 @@ string parseForParam(const string &arg, int argc, char** argv, bool argOnly)
return string(); return string();
} }
void waitForDetThreads(shared_t *share)
{
for (auto &&thr : share->detThreads)
{
thr.join();
}
share->detThreads.clear();
}

View File

@ -35,40 +35,38 @@ using namespace cv;
using namespace std; using namespace std;
using namespace std::filesystem; using namespace std::filesystem;
#define APP_VER "1.5.t15" #define APP_VER "1.5.t16"
#define APP_NAME "Motion Watch" #define APP_NAME "Motion Watch"
struct shared_t struct shared_t
{ {
vector<thread> detThreads;
ofstream recLogFile; ofstream recLogFile;
ofstream detLogFile; ofstream detLogFile;
string recLogPath; string recLogPath;
string detLogPath; string detLogPath;
string recordUrl; string recordUrl;
string outDir; string outDir;
string postCmd; string postCmd;
string conf; string conf;
string buffDir; string buffDir;
string vidExt; string vidExt;
string vidCodec; string vidCodec;
string camName; string camName;
string webBg; string webBg;
string webTxt; string webTxt;
string webFont; string webFont;
string webRoot; string webRoot;
bool init; bool init;
bool recLoopWait; bool skipCmd;
bool logRun; int frameGap;
bool skipCmd; int pixThresh;
int frameGap; int imgThresh;
int pixThresh; int secs;
int imgThresh; int maxDays;
int secs; int maxClips;
int maxDays; int maxLogSize;
int maxClips; int retCode;
int maxLogSize;
int retCode;
}; };
string genDstFile(const string &dirOut, const char *fmt, const string &ext); string genDstFile(const string &dirOut, const char *fmt, const string &ext);
@ -82,6 +80,7 @@ void enforceMaxClips(const string &dirPath, shared_t *share);
void rdLine(const string &param, const string &line, string *value); void rdLine(const string &param, const string &line, string *value);
void rdLine(const string &param, const string &line, int *value); void rdLine(const string &param, const string &line, int *value);
void statOut(shared_t *share); void statOut(shared_t *share);
void waitForDetThreads(shared_t *share);
bool rdConf(shared_t *share); bool rdConf(shared_t *share);
vector<string> lsFilesInDir(const string &path, const string &ext = string()); vector<string> lsFilesInDir(const string &path, const string &ext = string());
vector<string> lsDirsInDir(const string &path); vector<string> lsDirsInDir(const string &path);

View File

@ -13,57 +13,24 @@
#include "mo_detect.h" #include "mo_detect.h"
#include "logger.h" #include "logger.h"
void detectLoop(shared_t *share) void detectMoInFile(const string &bufPath, shared_t *share)
{ {
detLog("detect_loop() -- start", share); detLog("detect_mo_in_file() -- start", share);
vector<string> bufFiles; Mat thumbNail;
auto waitingForFiles = 0;
do if (moDetect(bufPath, thumbNail, share))
{ {
bufFiles = lsFilesInDir(share->buffDir, "." + share->vidExt); share->skipCmd = true;
// this loop will not process the last buffile while recLoop is still actively wrOut(bufPath, thumbNail, share);
// pulling footage from ffmpeg. it is assumed the last file is not finished. }
// share->recLoopWait is used to detect if the recloop is still pulling. if not else if (exists(bufPath))
// then the last file is finally processed. {
remove(bufPath);
if ((bufFiles.size() >= 2) || (share->recLoopWait && !bufFiles.empty()))
{
auto fullPath = cleanDir(share->buffDir) + "/" + bufFiles[0];
Mat thumbNail;
if (moDetect(fullPath, thumbNail, share))
{
share->skipCmd = true;
wrOut(fullPath, thumbNail, share);
}
else if (exists(fullPath))
{
remove(fullPath);
}
}
else
{
if (waitingForFiles >= share->secs)
{
detLog("timed out waiting for buff files from ffmpeg, did it fail?", share);
break;
}
else
{
detLog(to_string(bufFiles.size()) + " buff file(s) found, waiting for more.", share);
}
sleep(5); waitingForFiles += 5;
}
} }
while (!share->recLoopWait || !bufFiles.empty());
detLog("detect_loop() -- finished", share); detLog("detect_mo_in_file() -- finished", share);
} }
void recLoop(shared_t *share) void recLoop(shared_t *share)
@ -99,29 +66,39 @@ void recLoop(shared_t *share)
recLog("camera specific webroot page updated: " + share->outDir + "/index.html", share); recLog("camera specific webroot page updated: " + share->outDir + "/index.html", share);
auto bufPath = cleanDir(share->buffDir) + "/%03d." + share->vidExt; for (auto i = 0; i < share->secs; i += 10)
auto secs = to_string(share->secs); {
auto limSecs = to_string(share->secs + 3); auto bufPath = cleanDir(share->buffDir) + "/" + to_string(i) + "." + share->vidExt;
auto cmd = "timeout -k 1 " + limSecs + " ffmpeg -hide_banner -i " + share->recordUrl + " -y -vcodec " + share->vidCodec + " -movflags faststart -map 0 -segment_time 00:00:10 -f segment -t " + secs + " " + bufPath; auto cmd = "ffmpeg -hide_banner -i " + share->recordUrl + " -y vcodec " + share->vidCodec + " -movflags faststart -t 10 " + bufPath;
thread th2(detectLoop, share); recLog("ffmpeg_run: " + cmd, share);
recLog("detect_loop() -- started in a seperate thread.", share); auto retCode = system(cmd.c_str());
recLog("ffmpeg_run: " + cmd, share);
auto retCode = system(cmd.c_str()); recLog("ffmpeg_retcode: " + to_string(retCode), share);
recLog("ffmpeg_retcode: " + to_string(retCode), share); if (retCode == 0)
{
recLog("detect_mo_in_file() -- started in a seperate thread.", share);
share->recLoopWait = true; share->detThreads.push_back(thread(detectMoInFile, bufPath, share));
}
else
{
recLog("ffmpeg returned non zero, indicating failure. please check stderr output.", share);
th2.join(); if (exists(bufPath))
{
remove(bufPath);
}
}
}
recLog("detect_loop() -- thread finished.", share); waitForDetThreads(share);
if (!share->skipCmd) if (!share->skipCmd)
{ {
recLog("motion not detected by the detection loop.", share); recLog("no motion detected", share);
if (share->postCmd.empty()) if (share->postCmd.empty())
{ {
@ -135,7 +112,7 @@ void recLoop(shared_t *share)
} }
else else
{ {
recLog("motion detected by the detection loop, skipping the post command.", share); recLog("motion detected, skipping the post command.", share);
} }
recLog("rec_loop() -- finished", share); recLog("rec_loop() -- finished", share);
@ -171,11 +148,9 @@ int main(int argc, char** argv)
} }
else else
{ {
sharedRes.retCode = 0; sharedRes.retCode = 0;
sharedRes.recLoopWait = false; sharedRes.skipCmd = false;
sharedRes.skipCmd = false; sharedRes.init = true;
sharedRes.init = true;
sharedRes.logRun = true;
recLoop(&sharedRes); recLoop(&sharedRes);

View File

@ -123,7 +123,7 @@ bool moDetect(const string &buffFile, Mat &vidThumb, shared_t *share)
if (imgDiff(prev, next, share)) if (imgDiff(prev, next, share))
{ {
resize(next, vidThumb, Size(1280, 720), INTER_LINEAR); resize(next, vidThumb, Size(720, 480), INTER_LINEAR);
mod = true; break; mod = true; break;
} }