Somewhere in the code is causing an infinite loop, root cause still
undermined. added more logging statements to help me find misbehavior.
imgDiff() will now handle empty frames on the parameters more
gracefully.

enforceMaxClips() will no longer assume all video clips are accompanied
by html and jpg files but will now instead "delete if exists."
This commit is contained in:
Maurice ONeal 2022-12-16 18:24:18 -05:00
parent a5ee164b4e
commit c153fdcd21
4 changed files with 74 additions and 57 deletions

View File

@ -111,20 +111,20 @@ void enforceMaxDays(const string &dirPath, shared_t *share)
void enforceMaxClips(const string &dirPath, shared_t *share) void enforceMaxClips(const string &dirPath, shared_t *share)
{ {
auto names = lsDirsInDir(dirPath); auto names = lsFilesInDir(dirPath, "." + share->vidExt);
// note: this function assumes all video clips are accompanied by while (names.size() > share->maxClips)
// .html and .jpg files of the same name, hence why it *3
// the max names in the directory and *3 the file deletion.
while (names.size() > ((share->maxClips - 1) * 3))
{ {
remove(string(cleanDir(dirPath) + "/" + names[0]).c_str()); // removes the video file extension.
remove(string(cleanDir(dirPath) + "/" + names[1]).c_str()); auto nameOnly = names[0].substr(0, names[0].size() - (share->vidExt.size() + 1));
remove(string(cleanDir(dirPath) + "/" + names[2]).c_str()); auto imgFile = cleanDir(dirPath) + "/" + nameOnly + ".jpg";
auto webFile = cleanDir(dirPath) + "/" + nameOnly + ".html";
remove(cleanDir(dirPath) + "/" + names[0]);
if (exists(imgFile)) remove(imgFile);
if (exists(webFile)) remove(webFile);
names.erase(names.begin());
names.erase(names.begin());
names.erase(names.begin()); names.erase(names.begin());
} }
} }
@ -191,12 +191,12 @@ bool rdConf(shared_t *share)
share->retCode = 0; share->retCode = 0;
share->frameGap = 10; share->frameGap = 10;
share->pixThresh = 30; share->pixThresh = 150;
share->imgThresh = 512; share->imgThresh = 1024;
share->secs = 60; share->secs = 60;
share->maxDays = 15; share->maxDays = 15;
share->maxClips = 30; share->maxClips = 30;
share->maxLogSize = 10000; share->maxLogSize = 50000;
share->camName = path(share->conf.c_str()).filename(); share->camName = path(share->conf.c_str()).filename();
share->webRoot = "/var/www/html"; share->webRoot = "/var/www/html";
share->vidExt = "mp4"; share->vidExt = "mp4";

View File

@ -35,7 +35,7 @@ using namespace cv;
using namespace std; using namespace std;
using namespace std::filesystem; using namespace std::filesystem;
#define APP_VER "1.5.t9" #define APP_VER "1.5.t10"
#define APP_NAME "Motion Watch" #define APP_NAME "Motion Watch"
struct shared_t struct shared_t

View File

@ -15,7 +15,7 @@
void detectLoop(shared_t *share) void detectLoop(shared_t *share)
{ {
detLog("detectLoop() -- start", share); detLog("detect_loop() -- start", share);
vector<string> bufFiles; vector<string> bufFiles;
auto waitingForFiles = 0; auto waitingForFiles = 0;
@ -32,24 +32,17 @@ void detectLoop(shared_t *share)
if ((bufFiles.size() >= 2) || (share->recLoopWait && !bufFiles.empty())) if ((bufFiles.size() >= 2) || (share->recLoopWait && !bufFiles.empty()))
{ {
auto fullPath = cleanDir(share->buffDir) + "/" + bufFiles[0]; auto fullPath = cleanDir(share->buffDir) + "/" + bufFiles[0];
Mat thumbNail;
Mat thumbNail;
if (moDetect(fullPath, thumbNail, share)) if (moDetect(fullPath, thumbNail, share))
{ {
share->skipCmd = true; share->skipCmd = true;
detLog("motion detected in file: " + fullPath, share);
wrOut(fullPath, thumbNail, share); wrOut(fullPath, thumbNail, share);
} }
else else if (exists(fullPath))
{ {
detLog("no motion detected in file: " + fullPath + " removing it.", share); remove(fullPath);
if (exists(fullPath))
{
remove(fullPath);
}
} }
} }
else else
@ -60,19 +53,25 @@ void detectLoop(shared_t *share)
break; break;
} }
else
{
detLog(to_string(bufFiles.size()) + " buff file(s) found, waiting for more.", share);
}
sleep(1); waitingForFiles++; sleep(5); waitingForFiles += 5;
} }
} }
while (!bufFiles.empty() && !share->recLoopWait); while (!share->recLoopWait || !bufFiles.empty());
detLog("detectLoop() -- finished", share); detLog("detect_loop() -- finished", share);
} }
void recLoop(shared_t *share) void recLoop(shared_t *share)
{ {
while (rdConf(share)) while (rdConf(share))
{ {
recLog("rec_loop() -- start", share);
enforceMaxLogSize(share->recLogPath, share); enforceMaxLogSize(share->recLogPath, share);
enforceMaxLogSize(share->detLogPath, share); enforceMaxLogSize(share->detLogPath, share);
@ -81,28 +80,24 @@ void recLoop(shared_t *share)
initLogFrontPages(share); initLogFrontPages(share);
recLog("recLoop() -- start", share);
if (!exists("/tmp/mow-lock")) if (!exists("/tmp/mow-lock"))
{ {
recLog("/tmp/mow-lock not found, assuming it is safe to update the webroot page.", share);
recLog("webroot page = " + cleanDir(share->webRoot) + "/index.html", share);
system("touch /tmp/mow-lock"); system("touch /tmp/mow-lock");
genCSS(share); genCSS(share);
genHTMLul(share->webRoot, string(APP_NAME) + " " + string(APP_VER), share); genHTMLul(share->webRoot, string(APP_NAME) + " " + string(APP_VER), share);
remove("/tmp/mow-lock"); remove("/tmp/mow-lock");
recLog("webroot page updated: " + cleanDir(share->webRoot) + "/index.html", share);
} }
else else
{ {
recLog("/tmp/mow-lock pesent, skipping update of the webroot page.", share); recLog("skipping update of the webroot page, it is busy.", share);
} }
genHTMLul(share->outDir, share->camName, share); genHTMLul(share->outDir, share->camName, share);
recLog("camera specific webroot page updated. page = " + share->outDir + "/index.html", share); recLog("camera specific webroot page updated: " + share->outDir + "/index.html", share);
auto bufPath = cleanDir(share->buffDir) + "/%03d." + share->vidExt; auto bufPath = cleanDir(share->buffDir) + "/%03d." + share->vidExt;
auto secs = to_string(share->secs); auto secs = to_string(share->secs);
@ -111,7 +106,7 @@ void recLoop(shared_t *share)
thread th2(detectLoop, share); thread th2(detectLoop, share);
recLog("detectLoop() -- started in a seperate thread.", share); recLog("detect_loop() -- started in a seperate thread.", share);
recLog("ffmpeg_run: " + cmd, share); recLog("ffmpeg_run: " + cmd, share);
auto retCode = system(cmd.c_str()); auto retCode = system(cmd.c_str());
@ -122,6 +117,8 @@ void recLoop(shared_t *share)
th2.join(); th2.join();
recLog("detect_loop() -- thread finished.", share);
if (!share->skipCmd) if (!share->skipCmd)
{ {
recLog("motion not detected by the detection loop.", share); recLog("motion not detected by the detection loop.", share);
@ -132,7 +129,7 @@ void recLoop(shared_t *share)
} }
else else
{ {
recLog("running post command = " + share->postCmd, share); recLog("running post command: " + share->postCmd, share);
system(share->postCmd.c_str()); system(share->postCmd.c_str());
} }
} }
@ -141,7 +138,7 @@ void recLoop(shared_t *share)
recLog("motion detected by the detection loop, skipping the post command.", share); recLog("motion detected by the detection loop, skipping the post command.", share);
} }
recLog("recLoop() -- finished", share); recLog("rec_loop() -- finished", share);
if (share->retCode != 0) if (share->retCode != 0)
{ {

View File

@ -14,14 +14,30 @@
bool imgDiff(const Mat &prev, const Mat &next, int &diffScore, shared_t *share) bool imgDiff(const Mat &prev, const Mat &next, int &diffScore, shared_t *share)
{ {
Mat diff; auto ret = false;
absdiff(prev, next, diff); detLog("img_diff() -- start()", share);
threshold(diff, diff, share->pixThresh, 255, THRESH_BINARY);
diffScore = countNonZero(diff); if (prev.empty()) detLog("prev_frame is empty -- this should never happen (opencv to blame).", share);
if (next.empty()) detLog("next_frame is empty -- EOF assumed.", share);
return diffScore >= share->imgThresh; if (!prev.empty() && !next.empty())
{
Mat diff;
absdiff(prev, next, diff);
threshold(diff, diff, share->pixThresh, 255, THRESH_BINARY);
diffScore = countNonZero(diff);
detLog("diff_score: " + to_string(diffScore), share);
ret = diffScore >= share->imgThresh;
}
detLog("img_diff() -- finished()", share);
return ret;
} }
Mat frameFF(VideoCapture *cap, int gap) Mat frameFF(VideoCapture *cap, int gap)
@ -47,6 +63,9 @@ Mat frameFF(VideoCapture *cap, int gap)
void wrOut(const string &buffFile, const Mat &vidThumb, shared_t *share) void wrOut(const string &buffFile, const Mat &vidThumb, shared_t *share)
{ {
detLog("wr_out() -- start()", share);
detLog("buff_file: " + buffFile, share);
auto dayStr = genTimeStr("%Y-%m-%d"); auto dayStr = genTimeStr("%Y-%m-%d");
auto timStr = genTimeStr("%H%M%S"); auto timStr = genTimeStr("%H%M%S");
auto outDir = cleanDir(share->outDir) + "/" + dayStr; auto outDir = cleanDir(share->outDir) + "/" + dayStr;
@ -61,7 +80,6 @@ void wrOut(const string &buffFile, const Mat &vidThumb, shared_t *share)
detLog("write_out_vid: " + vidOut, share); detLog("write_out_vid: " + vidOut, share);
detLog("write_out_img: " + imgOut, share); detLog("write_out_img: " + imgOut, share);
detLog("remove_file: " + buffFile, share);
enforceMaxClips(outDir, share); enforceMaxClips(outDir, share);
@ -73,10 +91,15 @@ void wrOut(const string &buffFile, const Mat &vidThumb, shared_t *share)
genHTMLvid(vidOut, share); genHTMLvid(vidOut, share);
genHTMLul(outDir, share->camName + ": " + dayStr, share); genHTMLul(outDir, share->camName + ": " + dayStr, share);
genHTMLul(share->outDir, share->camName, share); genHTMLul(share->outDir, share->camName, share);
detLog("wr_out() -- finished()", share);
} }
bool moDetect(const string &buffFile, Mat &vidThumb, shared_t *share) 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;
VideoCapture capture(buffFile.c_str()); VideoCapture capture(buffFile.c_str());
@ -100,24 +123,21 @@ bool moDetect(const string &buffFile, Mat &vidThumb, shared_t *share)
{ {
resize(next, vidThumb, Size(1280, 720), INTER_LINEAR); resize(next, vidThumb, Size(1280, 720), INTER_LINEAR);
if (diff > maxDiff) mod = true;
{
maxDiff = diff;
}
mod = true; break;
} }
frameGaps++; frameGaps += share->frameGap;
}
while (!prev.empty() && !next.empty());
detLog("scanned_buff_file = " + buffFile + " max_score = " + to_string(maxDiff) + " frame_gaps = " + to_string(frameGaps), share); detLog("frame_gap: " + to_string(frameGaps), share);
}
while (!prev.empty() && !next.empty() && !mod);
} }
else else
{ {
detLog("failed to open buff file: " + buffFile + " for reading. check permissions and/or opencv's video-io support (gstreamer/ffmpeg).", share); detLog("failed to open the buff file for reading. check permissions and/or opencv's video-io support (gstreamer/ffmpeg).", share);
} }
detLog("mo_detect() -- finished()", share);
return mod; return mod;
} }