2022-09-22 20:57:46 -04:00
|
|
|
// This file is part of Motion Watch.
|
2022-04-14 09:45:54 -04:00
|
|
|
|
2022-09-22 20:57:46 -04:00
|
|
|
// 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.
|
2022-04-14 09:45:54 -04:00
|
|
|
|
2022-09-22 20:57:46 -04:00
|
|
|
// 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.
|
2022-04-14 09:45:54 -04:00
|
|
|
|
2022-09-22 20:57:46 -04:00
|
|
|
#include "mo_detect.h"
|
2022-12-11 10:25:22 -05:00
|
|
|
#include "logger.h"
|
2023-03-05 16:07:07 -05:00
|
|
|
#include "web.h"
|
2022-08-12 21:46:36 -04:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
void detectMo(shared_t *share)
|
2022-04-14 09:45:54 -04:00
|
|
|
{
|
2023-03-05 16:07:07 -05:00
|
|
|
while (share->retCode == 0)
|
|
|
|
{
|
|
|
|
sleep(2);
|
|
|
|
detectMoInStream("stream.m3u8", share);
|
|
|
|
}
|
|
|
|
}
|
2022-12-11 10:25:22 -05:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
void eventLoop(shared_t *share)
|
|
|
|
{
|
|
|
|
while (share->retCode == 0)
|
2023-02-18 21:20:24 -05:00
|
|
|
{
|
2023-03-12 13:22:10 -04:00
|
|
|
for (auto it = share->recList.begin(); !share->recList.empty();)
|
2023-03-05 16:07:07 -05:00
|
|
|
{
|
2023-03-12 13:22:10 -04:00
|
|
|
auto evName = it->first;
|
|
|
|
auto event = it->second;
|
|
|
|
auto timeDiff = genEpoch() - event.createTime;
|
2023-03-05 16:07:07 -05:00
|
|
|
|
|
|
|
// future time protection. this should never occur but
|
|
|
|
// this is in place in case the system time is incorrect.
|
2023-03-12 13:22:10 -04:00
|
|
|
if (timeDiff > 0)
|
2023-03-05 16:07:07 -05:00
|
|
|
{
|
2023-03-12 13:22:10 -04:00
|
|
|
// wait at least 61 seconds before processing the event in
|
|
|
|
// queue.
|
|
|
|
if (timeDiff < 61) sleep(61 - timeDiff);
|
2023-02-07 23:19:41 -05:00
|
|
|
|
2023-03-12 13:22:10 -04:00
|
|
|
try
|
2023-03-05 16:07:07 -05:00
|
|
|
{
|
2023-03-12 15:27:53 -04:00
|
|
|
wrOutVod(event, share);
|
|
|
|
genHTMLvod(evName);
|
2023-03-12 13:22:10 -04:00
|
|
|
|
|
|
|
if (!exists(evName + ".jpg"))
|
|
|
|
{
|
|
|
|
imwrite(string(evName + ".jpg").c_str(), event.thumbnail);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (filesystem_error &ex)
|
|
|
|
{
|
|
|
|
recLog(string("err: ") + ex.what(), share);
|
2023-03-05 16:07:07 -05:00
|
|
|
}
|
|
|
|
|
2023-03-12 13:22:10 -04:00
|
|
|
share->recList.erase(it);
|
|
|
|
}
|
2023-03-05 16:07:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
sleep(5);
|
2023-02-07 23:19:41 -05:00
|
|
|
}
|
2023-03-05 16:07:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void schLoop(shared_t *share)
|
|
|
|
{
|
|
|
|
if (!share->postCmd.empty())
|
2023-02-07 23:19:41 -05:00
|
|
|
{
|
2023-03-05 16:07:07 -05:00
|
|
|
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());
|
2023-02-18 21:20:24 -05:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
share->postCmdRunning = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
share->skipCmd = false;
|
|
|
|
|
|
|
|
detLog("motion detected, skipping the post command.", share);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-07 23:19:41 -05:00
|
|
|
}
|
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
void upkeep(shared_t *share)
|
2022-08-12 21:46:36 -04:00
|
|
|
{
|
2023-03-05 16:07:07 -05:00
|
|
|
while (share->retCode == 0)
|
2022-08-12 21:46:36 -04:00
|
|
|
{
|
2023-03-10 19:05:54 -05:00
|
|
|
enforceMaxLogSize(REC_LOG_NAME, share);
|
|
|
|
enforceMaxLogSize(DET_LOG_NAME, share);
|
|
|
|
enforceMaxLogSize(UPK_LOG_NAME, share);
|
2022-12-13 20:27:32 -05:00
|
|
|
|
2023-03-10 19:05:54 -05:00
|
|
|
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();
|
2022-12-13 20:27:32 -05:00
|
|
|
|
|
|
|
initLogFrontPages(share);
|
2023-03-05 16:07:07 -05:00
|
|
|
enforceMaxEvents(share);
|
|
|
|
cleanupEmptyDirs("VIDEO_TS");
|
|
|
|
|
|
|
|
genHTMLul(".", share->camName, share);
|
|
|
|
|
|
|
|
upkLog("camera specific webroot page updated: " + share->outDir + "/index.html", share);
|
2022-12-13 20:27:32 -05:00
|
|
|
|
2023-02-18 21:20:24 -05:00
|
|
|
if (!exists("/tmp/mow-lock"))
|
2022-12-04 15:13:39 -05:00
|
|
|
{
|
|
|
|
system("touch /tmp/mow-lock");
|
2022-12-13 20:27:32 -05:00
|
|
|
|
2022-12-11 10:25:22 -05:00
|
|
|
genCSS(share);
|
|
|
|
genHTMLul(share->webRoot, string(APP_NAME) + " " + string(APP_VER), share);
|
2022-12-13 20:27:32 -05:00
|
|
|
|
|
|
|
remove("/tmp/mow-lock");
|
2023-03-05 16:07:07 -05:00
|
|
|
upkLog("webroot page updated: " + cleanDir(share->webRoot) + "/index.html", share);
|
2023-02-18 21:20:24 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-05 16:07:07 -05:00
|
|
|
upkLog("skipping update of the webroot page, it is busy.", share);
|
2022-12-11 10:25:22 -05:00
|
|
|
}
|
2022-09-23 21:50:06 -04:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
sleep(60);
|
|
|
|
}
|
|
|
|
}
|
2023-02-07 23:19:41 -05:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
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'" +
|
2023-03-10 19:05:54 -05:00
|
|
|
" -y -vcodec copy" +
|
2023-03-05 16:07:07 -05:00
|
|
|
" -f hls -hls_time 6 -hls_list_size " +
|
|
|
|
to_string((share->maxDays * 86400) / 6) + // 86400 seconds in a day.
|
|
|
|
" stream.m3u8";
|
2023-02-18 17:43:10 -05:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
recLog("ffmpeg_run: " + cmd, share);
|
2022-07-28 10:30:07 -04:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
auto retCode = system(cmd.c_str());
|
2023-02-14 19:29:02 -05:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
recLog("ffmpeg_retcode: " + to_string(retCode), share);
|
2022-12-13 20:27:32 -05:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
if (retCode != 0)
|
2022-12-11 10:25:22 -05:00
|
|
|
{
|
2023-03-05 16:07:07 -05:00
|
|
|
recLog("err: ffmpeg returned non zero, indicating failure. please check stderr output.", share);
|
2022-12-11 10:25:22 -05:00
|
|
|
}
|
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
sleep(60);
|
2022-12-13 20:27:32 -05:00
|
|
|
}
|
2022-07-08 15:24:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
2022-09-22 20:57:46 -04:00
|
|
|
struct shared_t sharedRes;
|
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
sharedRes.conf = parseForParam("-c", argc, argv, false);
|
2022-07-08 15:24:45 -04:00
|
|
|
|
|
|
|
if (parseForParam("-h", argc, argv, true) == "true")
|
2022-04-14 09:45:54 -04:00
|
|
|
{
|
2022-09-23 21:50:06 -04:00
|
|
|
cout << "Motion Watch " << APP_VER << endl << endl;
|
2022-09-22 20:57:46 -04:00
|
|
|
cout << "Usage: mow <argument>" << endl << endl;
|
|
|
|
cout << "-h : display usage information about this application." << endl;
|
2023-03-05 16:07:07 -05:00
|
|
|
cout << "-c : path to the config file." << endl;
|
2022-12-24 13:48:51 -05:00
|
|
|
cout << "-v : display the current version." << endl << endl;
|
2022-09-23 21:50:06 -04:00
|
|
|
}
|
2022-12-04 15:13:39 -05:00
|
|
|
else if (parseForParam("-v", argc, argv, true) == "true")
|
2022-09-23 21:50:06 -04:00
|
|
|
{
|
|
|
|
cout << APP_VER << endl;
|
2022-04-14 09:45:54 -04:00
|
|
|
}
|
2022-07-08 15:24:45 -04:00
|
|
|
else if (sharedRes.conf.empty())
|
2022-04-14 09:45:54 -04:00
|
|
|
{
|
2023-02-18 21:20:24 -05:00
|
|
|
cerr << "err: no config file(s) were given in -c" << endl;
|
2022-04-14 09:45:54 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-05 16:07:07 -05:00
|
|
|
sharedRes.retCode = 0;
|
|
|
|
sharedRes.skipCmd = false;
|
|
|
|
sharedRes.postCmdRunning = false;
|
|
|
|
|
|
|
|
rdConf(&sharedRes);
|
|
|
|
|
|
|
|
if (exists("VIDEO_TS/live"))
|
|
|
|
{
|
|
|
|
remove_all("VIDEO_TS/live");
|
|
|
|
}
|
2022-12-11 10:25:22 -05:00
|
|
|
|
2023-03-05 16:07:07 -05:00
|
|
|
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();
|
2022-04-14 09:45:54 -04:00
|
|
|
|
2022-07-08 15:24:45 -04:00
|
|
|
return sharedRes.retCode;
|
2022-04-14 09:45:54 -04:00
|
|
|
}
|
|
|
|
|
2022-07-08 15:24:45 -04:00
|
|
|
return EINVAL;
|
2022-04-14 09:45:54 -04:00
|
|
|
}
|