Compare commits
4 Commits
ff5f95f445
...
25528617d5
Author | SHA1 | Date | |
---|---|---|---|
|
25528617d5 | ||
|
ad733f8317 | ||
|
c17f74bea9 | ||
|
5f9c4be6b2 |
|
@ -40,6 +40,11 @@ web_root = /var/www/html
|
||||||
# warning: this will overwrite any existing index.html files so be sure
|
# warning: this will overwrite any existing index.html files so be sure
|
||||||
# to choose a directory that doesn't have an existing website.
|
# to choose a directory that doesn't have an existing website.
|
||||||
#
|
#
|
||||||
|
buffer_path = /tmp
|
||||||
|
# this is the work directory the app will use to store live footage and
|
||||||
|
# image frames. it's recommended to use a ram disk for this since there
|
||||||
|
# will be large amounts of io occuring here.
|
||||||
|
#
|
||||||
cam_name = cam-1
|
cam_name = cam-1
|
||||||
# this is the optional camera name parameter to identify the camera. this
|
# this is the optional camera name parameter to identify the camera. this
|
||||||
# name will also be used to as the base directory in web_root. if not
|
# name will also be used to as the base directory in web_root. if not
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
apt install apache2
|
|
||||||
if [ ! -d "/opt/mow" ]; then
|
if [ ! -d "/opt/mow" ]; then
|
||||||
mkdir /opt/mow
|
mkdir /opt/mow
|
||||||
fi
|
fi
|
||||||
cp ./.build-mow/mow /opt/mow/bin
|
cp ./.build-mow/mow /opt/mow/bin
|
||||||
printf "#!/bin/sh\n" > /opt/mow/run
|
printf "#!/bin/sh\n" > /opt/mow/run
|
||||||
printf "export OPENCV_LOG_LEVEL=DEBUG\n" >> /opt/mow/run
|
|
||||||
printf "export OPENCV_VIDEOIO_DEBUG=1\n" >> /opt/mow/run
|
|
||||||
printf "/opt/mow/bin \$1 \$2 \$3\n" >> /opt/mow/run
|
printf "/opt/mow/bin \$1 \$2 \$3\n" >> /opt/mow/run
|
||||||
chmod +x /opt/mow/run
|
chmod +x /opt/mow/run
|
||||||
chmod +x /opt/mow/bin
|
chmod +x /opt/mow/bin
|
||||||
|
|
|
@ -25,6 +25,7 @@ Camera::Camera(QObject *parent) : QObject(parent)
|
||||||
shared.skipCmd = false;
|
shared.skipCmd = false;
|
||||||
shared.postSecs = 60;
|
shared.postSecs = 60;
|
||||||
shared.evMaxSecs = 30;
|
shared.evMaxSecs = 30;
|
||||||
|
shared.buffPath = QDir::tempPath();
|
||||||
shared.webRoot = "/var/www/html";
|
shared.webRoot = "/var/www/html";
|
||||||
shared.webBg = "#485564";
|
shared.webBg = "#485564";
|
||||||
shared.webTxt = "#dee5ee";
|
shared.webTxt = "#dee5ee";
|
||||||
|
@ -37,14 +38,6 @@ int Camera::start(const QStringList &args)
|
||||||
|
|
||||||
if (rdConf(&shared))
|
if (rdConf(&shared))
|
||||||
{
|
{
|
||||||
QDir("live").removeRecursively();
|
|
||||||
QDir("img").removeRecursively();
|
|
||||||
|
|
||||||
QDir().mkdir("live");
|
|
||||||
QDir().mkdir("events");
|
|
||||||
QDir().mkdir("logs");
|
|
||||||
QDir().mkdir("img");
|
|
||||||
|
|
||||||
auto thr1 = new QThread(nullptr);
|
auto thr1 = new QThread(nullptr);
|
||||||
auto thr2 = new QThread(nullptr);
|
auto thr2 = new QThread(nullptr);
|
||||||
auto thr3 = new QThread(nullptr);
|
auto thr3 = new QThread(nullptr);
|
||||||
|
@ -215,11 +208,6 @@ Upkeep::Upkeep(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(shared
|
||||||
|
|
||||||
bool Upkeep::exec()
|
bool Upkeep::exec()
|
||||||
{
|
{
|
||||||
QDir().mkdir("live");
|
|
||||||
QDir().mkdir("events");
|
|
||||||
QDir().mkdir("logs");
|
|
||||||
QDir().mkdir("img");
|
|
||||||
|
|
||||||
enforceMaxLogSize(QString("logs/") + REC_LOG_NAME, shared);
|
enforceMaxLogSize(QString("logs/") + REC_LOG_NAME, shared);
|
||||||
enforceMaxLogSize(QString("logs/") + DET_LOG_NAME, shared);
|
enforceMaxLogSize(QString("logs/") + DET_LOG_NAME, shared);
|
||||||
|
|
||||||
|
@ -253,7 +241,7 @@ EventLoop::EventLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(
|
||||||
|
|
||||||
bool EventLoop::exec()
|
bool EventLoop::exec()
|
||||||
{
|
{
|
||||||
if (cycles * 2 >= shared->evMaxSecs)
|
if (!vidList.isEmpty())
|
||||||
{
|
{
|
||||||
vidList.removeDuplicates();
|
vidList.removeDuplicates();
|
||||||
|
|
||||||
|
@ -282,32 +270,46 @@ bool EventLoop::exec()
|
||||||
|
|
||||||
vidList.clear();
|
vidList.clear();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
shared->recMutex.lock();
|
||||||
|
|
||||||
|
QList<int> rmIndx;
|
||||||
|
|
||||||
|
for (auto i = 0; i < shared->recList.size(); ++i)
|
||||||
{
|
{
|
||||||
cycles += 1;
|
auto event = &shared->recList[i];
|
||||||
|
|
||||||
shared->recMutex.lock();
|
if (highScore < event->score)
|
||||||
|
|
||||||
for (auto &&event : shared->recList)
|
|
||||||
{
|
{
|
||||||
auto maxFiles = shared->evMaxSecs / 2;
|
name = event->timeStamp.toString(DATETIME_FMT);
|
||||||
// there's 2 secs in each hls segment
|
imgPath = event->imgPath;
|
||||||
|
highScore = event->score;
|
||||||
if (highScore < event.score)
|
|
||||||
{
|
|
||||||
name = event.timeStamp.toString(DATETIME_FMT);
|
|
||||||
imgPath = event.imgPath;
|
|
||||||
highScore = event.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
vidList.append(backwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2));
|
|
||||||
vidList.append(forwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared->recList.clear();
|
if (event->queAge >= (shared->evMaxSecs / heartBeat))
|
||||||
shared->recMutex.unlock();
|
{
|
||||||
|
auto maxSecs = shared->evMaxSecs / 2;
|
||||||
|
// half the maxsecs value to get front-back half secs
|
||||||
|
|
||||||
|
auto backFiles = backwardFacingFiles("live", ".ts", event->timeStamp, maxSecs);
|
||||||
|
auto frontFiles = forwardFacingFiles("live", ".ts", event->timeStamp, maxSecs);
|
||||||
|
|
||||||
|
vidList.append(backFiles + frontFiles);
|
||||||
|
rmIndx.append(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event->queAge += heartBeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto i : rmIndx)
|
||||||
|
{
|
||||||
|
shared->recList.removeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared->recMutex.unlock();
|
||||||
|
|
||||||
return Loop::exec();
|
return Loop::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,9 +379,9 @@ DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loo
|
||||||
{
|
{
|
||||||
pcTimer = 0;
|
pcTimer = 0;
|
||||||
heartBeat = 2;
|
heartBeat = 2;
|
||||||
delayCycles = 8; // this will be used to delay the
|
delayCycles = 12; // this will be used to delay the
|
||||||
// actual start of DetectLoop by
|
// actual start of DetectLoop by
|
||||||
// 16secs.
|
// 24secs.
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectLoop::init()
|
void DetectLoop::init()
|
||||||
|
@ -473,6 +475,7 @@ bool DetectLoop::exec()
|
||||||
event.timeStamp = curDT;
|
event.timeStamp = curDT;
|
||||||
event.score = score;
|
event.score = score;
|
||||||
event.imgPath = images[pos];
|
event.imgPath = images[pos];
|
||||||
|
event.queAge = 0;
|
||||||
|
|
||||||
shared->recMutex.lock();
|
shared->recMutex.lock();
|
||||||
shared->recList.append(event); mod = true;
|
shared->recList.append(event); mod = true;
|
||||||
|
|
|
@ -167,6 +167,21 @@ void rdLine(const QString ¶m, const QString &line, int *value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void touch(const QString &path)
|
||||||
|
{
|
||||||
|
if (!QFile::exists(path))
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
|
||||||
|
if (file.open(QFile::WriteOnly))
|
||||||
|
{
|
||||||
|
file.write("");
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool rdConf(const QString &filePath, shared_t *share)
|
bool rdConf(const QString &filePath, shared_t *share)
|
||||||
{
|
{
|
||||||
QFile varFile(filePath);
|
QFile varFile(filePath);
|
||||||
|
@ -189,6 +204,7 @@ bool rdConf(const QString &filePath, shared_t *share)
|
||||||
{
|
{
|
||||||
rdLine("cam_name = ", line, &share->camName);
|
rdLine("cam_name = ", line, &share->camName);
|
||||||
rdLine("recording_stream = ", line, &share->recordUrl);
|
rdLine("recording_stream = ", line, &share->recordUrl);
|
||||||
|
rdLine("buffer_path = ", line, &share->buffPath);
|
||||||
rdLine("web_root = ", line, &share->webRoot);
|
rdLine("web_root = ", line, &share->webRoot);
|
||||||
rdLine("web_text = ", line, &share->webTxt);
|
rdLine("web_text = ", line, &share->webTxt);
|
||||||
rdLine("web_bg = ", line, &share->webBg);
|
rdLine("web_bg = ", line, &share->webBg);
|
||||||
|
@ -217,10 +233,29 @@ bool rdConf(shared_t *share)
|
||||||
}
|
}
|
||||||
|
|
||||||
share->outDir = QDir().cleanPath(share->webRoot) + "/" + share->camName;
|
share->outDir = QDir().cleanPath(share->webRoot) + "/" + share->camName;
|
||||||
|
share->tmpDir = share->buffPath + "/" + APP_BIN + "/" + share->camName;
|
||||||
|
|
||||||
QDir().mkpath(share->outDir);
|
QDir().mkpath(share->outDir);
|
||||||
|
QDir().mkpath(share->tmpDir);
|
||||||
|
|
||||||
if (!QDir::setCurrent(share->outDir))
|
QDir().mkpath(share->outDir + "/events");
|
||||||
|
QDir().mkpath(share->tmpDir + "/live");
|
||||||
|
QDir().mkpath(share->tmpDir + "/logs");
|
||||||
|
QDir().mkpath(share->tmpDir + "/img");
|
||||||
|
|
||||||
|
touch(share->tmpDir + "/index.html");
|
||||||
|
touch(share->tmpDir + "/stream.html");
|
||||||
|
touch(share->tmpDir + "/stream.m3u8");
|
||||||
|
|
||||||
|
QFile::link(share->tmpDir + "/live", share->outDir + "/live");
|
||||||
|
QFile::link(share->tmpDir + "/logs", share->outDir + "/logs");
|
||||||
|
QFile::link(share->tmpDir + "/img", share->outDir + "/img");
|
||||||
|
QFile::link(share->tmpDir + "/index.html", share->outDir + "/index.html");
|
||||||
|
QFile::link(share->tmpDir + "/stream.html", share->outDir + "/stream.html");
|
||||||
|
QFile::link(share->tmpDir + "/stream.m3u8", share->outDir + "/stream.m3u8");
|
||||||
|
QFile::link(share->outDir + "/events", share->tmpDir + "/events");
|
||||||
|
|
||||||
|
if (!QDir::setCurrent(share->tmpDir))
|
||||||
{
|
{
|
||||||
QTextStream(stderr) << "err: failed to change/create the current working directory to camera folder: '" << share->outDir << "' does it exists?" << Qt::endl;
|
QTextStream(stderr) << "err: failed to change/create the current working directory to camera folder: '" << share->outDir << "' does it exists?" << Qt::endl;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define APP_VER "3.0.0"
|
#define APP_VER "3.1"
|
||||||
#define APP_NAME "Motion Watch"
|
#define APP_NAME "Motion Watch"
|
||||||
#define APP_BIN "mow"
|
#define APP_BIN "mow"
|
||||||
#define REC_LOG_NAME "rec_log_lines.html"
|
#define REC_LOG_NAME "rec_log_lines.html"
|
||||||
|
@ -45,6 +45,7 @@ struct evt_t
|
||||||
QDateTime timeStamp;
|
QDateTime timeStamp;
|
||||||
QString imgPath;
|
QString imgPath;
|
||||||
float score;
|
float score;
|
||||||
|
uint queAge;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct shared_t
|
struct shared_t
|
||||||
|
@ -57,6 +58,8 @@ struct shared_t
|
||||||
QString detLog;
|
QString detLog;
|
||||||
QString recordUrl;
|
QString recordUrl;
|
||||||
QString outDir;
|
QString outDir;
|
||||||
|
QString tmpDir;
|
||||||
|
QString buffPath;
|
||||||
QString postCmd;
|
QString postCmd;
|
||||||
QString camName;
|
QString camName;
|
||||||
QString webBg;
|
QString webBg;
|
||||||
|
@ -80,6 +83,7 @@ QStringList backwardFacingFiles(const QString &path, const QString &ext, const Q
|
||||||
QStringList forwardFacingFiles(const QString &path, const QString &ext, const QDateTime &stamp, int secs);
|
QStringList forwardFacingFiles(const QString &path, const QString &ext, const QDateTime &stamp, int secs);
|
||||||
bool rdConf(const QString &filePath, shared_t *share);
|
bool rdConf(const QString &filePath, shared_t *share);
|
||||||
bool rdConf(shared_t *share);
|
bool rdConf(shared_t *share);
|
||||||
|
void touch(const QString &path);
|
||||||
void rdLine(const QString ¶m, const QString &line, QString *value);
|
void rdLine(const QString ¶m, const QString &line, QString *value);
|
||||||
void rdLine(const QString ¶m, const QString &line, int *value);
|
void rdLine(const QString ¶m, const QString &line, int *value);
|
||||||
void enforceMaxEvents(shared_t *share);
|
void enforceMaxEvents(shared_t *share);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user