JustMotion/src/main.cpp
Maurice ONeal ae46834777 v2.0.t3
Event recordings are not writing out correctly. added more log lines to
help debug.
2023-03-10 19:35:44 -05:00

216 lines
6.0 KiB
C++
Executable File

// This file is part of Motion Watch.
// Motion Watch is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Motion Watch is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "mo_detect.h"
#include "logger.h"
#include "web.h"
void detectMo(shared_t *share)
{
while (share->retCode == 0)
{
sleep(2);
detectMoInStream("stream.m3u8", share);
}
}
void eventLoop(shared_t *share)
{
while (share->retCode == 0)
{
while (!share->recList.empty())
{
auto pls = share->recList[0];
auto timeDiff = pls.createTime - genEpoch();
// future time protection. this should never occur but
// this is in place in case the system time is incorrect.
if (timeDiff < 0) timeDiff = 0;
// wait at least 6 seconds before processing the event in
// queue.
if (timeDiff < 6) sleep(6 - timeDiff);
try
{
wrOutm3u8(pls);
genHTMLvid(pls.fileName);
if (!exists(pls.fileName + ".jpg"))
{
imwrite(string(pls.fileName + ".jpg").c_str(), pls.thumbnail);
}
}
catch (filesystem_error &ex)
{
recLog("err: " + ex.what(), share);
}
share->recList.erase(share->recList.begin());
}
sleep(5);
}
}
void schLoop(shared_t *share)
{
if (!share->postCmd.empty())
{
while (share->retCode == 0)
{
sleep(share->schSec);
if (!share->skipCmd)
{
share->postCmdRunning = true;
detLog("no motion detected, running post command: " + share->postCmd, share);
system(share->postCmd.c_str());
share->postCmdRunning = false;
}
else
{
share->skipCmd = false;
detLog("motion detected, skipping the post command.", share);
}
}
}
}
void upkeep(shared_t *share)
{
while (share->retCode == 0)
{
enforceMaxLogSize(REC_LOG_NAME, share);
enforceMaxLogSize(DET_LOG_NAME, share);
enforceMaxLogSize(UPK_LOG_NAME, share);
dumpLogs(REC_LOG_NAME, share->recLog);
dumpLogs(DET_LOG_NAME, share->detLog);
dumpLogs(UPK_LOG_NAME, share->upkLog);
share->recLog.clear();
share->detLog.clear();
share->upkLog.clear();
initLogFrontPages(share);
enforceMaxEvents(share);
cleanupEmptyDirs("VIDEO_TS");
genHTMLul(".", share->camName, share);
upkLog("camera specific webroot page updated: " + share->outDir + "/index.html", share);
if (!exists("/tmp/mow-lock"))
{
system("touch /tmp/mow-lock");
genCSS(share);
genHTMLul(share->webRoot, string(APP_NAME) + " " + string(APP_VER), share);
remove("/tmp/mow-lock");
upkLog("webroot page updated: " + cleanDir(share->webRoot) + "/index.html", share);
}
else
{
upkLog("skipping update of the webroot page, it is busy.", share);
}
sleep(60);
}
}
void recLoop(shared_t *share)
{
while (share->retCode == 0)
{
auto cmd = "ffmpeg -hide_banner -i " +
share->recordUrl +
" -strftime 1" +
" -strftime_mkdir 1" +
" -hls_segment_filename 'VIDEO_TS/live/%Y/%j/%H/%M%S.ts'" +
" -y -vcodec copy" +
" -f hls -hls_time 6 -hls_list_size " +
to_string((share->maxDays * 86400) / 6) + // 86400 seconds in a day.
" stream.m3u8";
recLog("ffmpeg_run: " + cmd, share);
auto retCode = system(cmd.c_str());
recLog("ffmpeg_retcode: " + to_string(retCode), share);
if (retCode != 0)
{
recLog("err: ffmpeg returned non zero, indicating failure. please check stderr output.", share);
}
sleep(60);
}
}
int main(int argc, char** argv)
{
struct shared_t sharedRes;
sharedRes.conf = parseForParam("-c", argc, argv, false);
if (parseForParam("-h", argc, argv, true) == "true")
{
cout << "Motion Watch " << APP_VER << endl << endl;
cout << "Usage: mow <argument>" << endl << endl;
cout << "-h : display usage information about this application." << endl;
cout << "-c : path to the config file." << endl;
cout << "-v : display the current version." << endl << endl;
}
else if (parseForParam("-v", argc, argv, true) == "true")
{
cout << APP_VER << endl;
}
else if (sharedRes.conf.empty())
{
cerr << "err: no config file(s) were given in -c" << endl;
}
else
{
sharedRes.retCode = 0;
sharedRes.skipCmd = false;
sharedRes.postCmdRunning = false;
rdConf(&sharedRes);
if (exists("VIDEO_TS/live"))
{
remove_all("VIDEO_TS/live");
}
auto thr1 = thread(recLoop, &sharedRes);
auto thr2 = thread(upkeep, &sharedRes);
auto thr3 = thread(detectMo, &sharedRes);
auto thr4 = thread(eventLoop, &sharedRes);
auto thr5 = thread(schLoop, &sharedRes);
thr1.join();
thr2.join();
thr3.join();
thr4.join();
thr5.join();
return sharedRes.retCode;
}
return EINVAL;
}