v3.3.t4
-completely reformed the eventloop code to be more efficent and removed the use backward/forward facing functions. -added the live_secs config option that limits the amount of live footage the app will record to the buffer directory. -moved away from ffmpeg hls formatting. live footage will instead just be recorded in clips inside of the 'live' directory, the stream.m3u8 file will not longer be created. doing this removes the codec/container limitations that hls imposed. -changed up the default conf values that better suits a low spec machine like a resberrypi.
This commit is contained in:
parent
525c342c0f
commit
60a24c9d67
278
src/camera.cpp
278
src/camera.cpp
|
@ -20,15 +20,12 @@ int Camera::start(const QStringList &args)
|
|||
{
|
||||
auto thr1 = new QThread(nullptr);
|
||||
auto thr2 = new QThread(nullptr);
|
||||
auto thr3 = new QThread(nullptr);
|
||||
|
||||
new Upkeep(&shared, thr1, nullptr);
|
||||
new EventLoop(&shared, thr2, nullptr);
|
||||
new DetectLoop(&shared, thr3, nullptr);
|
||||
new EventLoop(&shared, thr1, nullptr);
|
||||
new DetectLoop(&shared, thr2, nullptr);
|
||||
|
||||
thr1->start();
|
||||
thr2->start();
|
||||
thr3->start();
|
||||
}
|
||||
|
||||
return shared.retCode;
|
||||
|
@ -75,103 +72,22 @@ bool Loop::exec()
|
|||
return shared->retCode == 0;
|
||||
}
|
||||
|
||||
Upkeep::Upkeep(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent) {}
|
||||
|
||||
bool Upkeep::exec()
|
||||
{
|
||||
enforceMaxEvents(shared);
|
||||
enforceMaxImages(shared);
|
||||
enforceMaxVids(shared);
|
||||
|
||||
return Loop::exec();
|
||||
}
|
||||
|
||||
EventLoop::EventLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
||||
{
|
||||
heartBeat = 2;
|
||||
highScore = 0;
|
||||
cycles = 0;
|
||||
}
|
||||
|
||||
bool EventLoop::exec()
|
||||
bool EventLoop::wrOutVod(const evt_t &event)
|
||||
{
|
||||
if (!vidList.isEmpty())
|
||||
{
|
||||
vidList.removeDuplicates();
|
||||
|
||||
if (vidList.size() > 1)
|
||||
{
|
||||
QTextStream(stdout) << "attempting write out of event: " << name << Qt::endl;
|
||||
|
||||
if (wrOutVod())
|
||||
{
|
||||
QProcess proc;
|
||||
QStringList args;
|
||||
|
||||
args << "convert";
|
||||
args << imgPath;
|
||||
args << shared->recPath + "/" + name + shared->thumbExt;
|
||||
|
||||
proc.start("magick", args);
|
||||
proc.waitForFinished();
|
||||
}
|
||||
}
|
||||
|
||||
cycles = 0;
|
||||
highScore = 0;
|
||||
|
||||
vidList.clear();
|
||||
}
|
||||
|
||||
QList<int> rmIndx;
|
||||
|
||||
for (auto i = 0; i < shared->recList.size(); ++i)
|
||||
{
|
||||
auto event = &shared->recList[i];
|
||||
|
||||
if (highScore < event->score)
|
||||
{
|
||||
name = event->timeStamp.toString(DATETIME_FMT);
|
||||
imgPath = event->imgPath;
|
||||
highScore = event->score;
|
||||
}
|
||||
|
||||
if (event->queAge >= (shared->evMaxSecs / heartBeat))
|
||||
{
|
||||
auto maxSecs = shared->evMaxSecs / 2;
|
||||
// half the maxsecs value to get front-back half secs
|
||||
|
||||
auto backFiles = backwardFacingFiles(shared->buffPath + "/live", shared->streamExt, event->timeStamp, maxSecs);
|
||||
auto frontFiles = forwardFacingFiles(shared->buffPath + "/live", shared->streamExt, event->timeStamp, maxSecs);
|
||||
|
||||
vidList.append(backFiles + frontFiles);
|
||||
rmIndx.append(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
event->queAge += heartBeat;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i : rmIndx)
|
||||
{
|
||||
shared->recList.removeAt(i);
|
||||
}
|
||||
|
||||
return Loop::exec();
|
||||
}
|
||||
|
||||
bool EventLoop::wrOutVod()
|
||||
{
|
||||
auto cnt = 0;
|
||||
auto concat = name + ".tmp";
|
||||
auto ret = false;
|
||||
auto cnt = 0;
|
||||
auto concat = shared->buffPath + "/live/" + event.timeStamp + ".ctmp";
|
||||
|
||||
QFile file(concat);
|
||||
QFile file(concat, this);
|
||||
|
||||
file.open(QFile::WriteOnly);
|
||||
|
||||
for (auto &&vid : vidList)
|
||||
for (auto &&vid : event.vidList)
|
||||
{
|
||||
QTextStream(stdout) << "event_src: " << vid << Qt::endl;
|
||||
|
||||
|
@ -189,7 +105,7 @@ bool EventLoop::wrOutVod()
|
|||
|
||||
if (cnt == 0)
|
||||
{
|
||||
QTextStream(stderr) << "err: none of the event hls clips exists, canceling write out." << Qt::endl;
|
||||
QTextStream(stderr) << "err: none of the event hls clips exists, cancelling write out." << Qt::endl;
|
||||
|
||||
QFile::remove(concat);
|
||||
}
|
||||
|
@ -202,29 +118,59 @@ bool EventLoop::wrOutVod()
|
|||
args << "-safe" << "0";
|
||||
args << "-i" << concat;
|
||||
args << "-c" << "copy";
|
||||
args << shared->recPath + "/" + name + shared->recExt;
|
||||
args << shared->recPath + "/" + event.timeStamp + shared->recExt;
|
||||
|
||||
if (QProcess::execute("ffmpeg", args) == 0)
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
|
||||
QProcess::execute("ffmpeg", args);
|
||||
QFile::remove(concat);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool EventLoop::exec()
|
||||
{
|
||||
enforceMaxEvents(shared);
|
||||
enforceMaxImages(shared);
|
||||
enforceMaxClips(shared);
|
||||
|
||||
if (!shared->recList.isEmpty())
|
||||
{
|
||||
auto event = shared->recList.takeFirst();
|
||||
|
||||
QTextStream(stdout) << "attempting write out of event: " << event.timeStamp << Qt::endl;
|
||||
|
||||
if (wrOutVod(event))
|
||||
{
|
||||
QStringList args;
|
||||
|
||||
args << "convert";
|
||||
args << event.imgPath;
|
||||
args << shared->recPath + "/" + event.timeStamp + shared->thumbExt;
|
||||
|
||||
QProcess::execute("magick", args);
|
||||
}
|
||||
}
|
||||
|
||||
return Loop::exec();
|
||||
}
|
||||
|
||||
DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
||||
{
|
||||
seed = 0;
|
||||
pcTimer = 0;
|
||||
heartBeat = 2;
|
||||
delayCycles = 12; // this will be used to delay the
|
||||
// actual start of DetectLoop by
|
||||
// 24secs.
|
||||
pcTimer = 0;
|
||||
heartBeat = 2;
|
||||
}
|
||||
|
||||
void DetectLoop::init()
|
||||
{
|
||||
pcTimer = new QTimer(this);
|
||||
mod = false;
|
||||
|
||||
eventQue.queAge = 0;
|
||||
eventQue.score = 0;
|
||||
eventQue.inQue = false;
|
||||
|
||||
connect(pcTimer, &QTimer::timeout, this, &DetectLoop::pcBreak);
|
||||
|
||||
|
@ -244,15 +190,12 @@ void DetectLoop::pcBreak()
|
|||
{
|
||||
QTextStream(stdout) << "---POST_BREAK---" << Qt::endl;
|
||||
|
||||
if (mod)
|
||||
if (eventQue.inQue)
|
||||
{
|
||||
QTextStream(stdout) << "motion detected, skipping the post command." << Qt::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delayCycles == 0) delayCycles = 5;
|
||||
else delayCycles += 5;
|
||||
|
||||
QTextStream(stdout) << "no motion detected, running post command: " << shared->postCmd << Qt::endl;
|
||||
|
||||
auto args = parseArgs(shared->postCmd.toUtf8(), -1);
|
||||
|
@ -267,8 +210,6 @@ void DetectLoop::pcBreak()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod = false;
|
||||
}
|
||||
|
||||
float DetectLoop::getFloatFromExe(const QByteArray &line)
|
||||
|
@ -288,7 +229,16 @@ float DetectLoop::getFloatFromExe(const QByteArray &line)
|
|||
}
|
||||
}
|
||||
|
||||
return strNum.toFloat();
|
||||
auto ok = false;
|
||||
auto res = strNum.toFloat(&ok);
|
||||
|
||||
if (!ok || strNum.isEmpty())
|
||||
{
|
||||
QTextStream(stderr) << "err: the image comp command returned unexpected output and couldn't be converted to float." << Qt::endl;
|
||||
QTextStream(stderr) << " raw output: " << line << Qt::endl;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
QStringList DetectLoop::buildArgs(const QString &prev, const QString &next)
|
||||
|
@ -308,6 +258,7 @@ QStringList DetectLoop::buildSnapArgs(const QString &vidSrc, const QString &imgP
|
|||
{
|
||||
QStringList ret;
|
||||
|
||||
ret.append("-hide_banner");
|
||||
ret.append("-y");
|
||||
ret.append("-i");
|
||||
ret.append(vidSrc);
|
||||
|
@ -320,88 +271,95 @@ QStringList DetectLoop::buildSnapArgs(const QString &vidSrc, const QString &imgP
|
|||
|
||||
bool DetectLoop::exec()
|
||||
{
|
||||
if (delayCycles > 0)
|
||||
if (eventQue.inQue)
|
||||
{
|
||||
delayCycles -= 1;
|
||||
eventQue.queAge += heartBeat;
|
||||
}
|
||||
|
||||
QTextStream(stdout) << "delay: detection cycle skipped. cycles left to be skipped: " << QString::number(delayCycles) << Qt::endl;
|
||||
auto clips = lsFilesInDir(shared->buffPath + "/live", shared->streamExt);
|
||||
|
||||
if (clips.size() < 2)
|
||||
{
|
||||
QTextStream(stdout) << "warning: didn't pick up enough clips files from the video stream. number of files: " << QString::number(clips.size()) << Qt::endl;
|
||||
QTextStream(stdout) << " will try again on the next loop." << Qt::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto imgAPath = "img/" + QString::number(seed++) + ".bmp";
|
||||
auto imgBPath = "img/" + QString::number(seed++) + ".bmp";
|
||||
auto curDT = QDateTime::currentDateTime();
|
||||
auto clips = backwardFacingFiles("live", shared->streamExt, curDT, 16);
|
||||
auto vidAPath = shared->buffPath + "/live/" + clips[clips.size() - 2];
|
||||
auto vidBPath = shared->buffPath + "/live/" + clips[clips.size() - 1];
|
||||
auto imgAPath = shared->buffPath + "/img/" + QFileInfo(vidAPath).baseName() + ".bmp";
|
||||
auto imgBPath = shared->buffPath + "/img/" + QFileInfo(vidBPath).baseName() + ".bmp";
|
||||
auto snapArgsA = buildSnapArgs(vidAPath, imgAPath);
|
||||
auto snapArgsB = buildSnapArgs(vidBPath, imgBPath);
|
||||
auto compArgs = buildArgs(imgAPath, imgBPath);
|
||||
|
||||
if (clips.size() < 2)
|
||||
if (compArgs.isEmpty())
|
||||
{
|
||||
QTextStream(stdout) << "warning: didn't pick up enough clips files from the video stream. number of files: " << QString::number(clips.size()) << Qt::endl;
|
||||
QTextStream(stdout) << " will try again on the next loop." << Qt::endl;
|
||||
QTextStream(stderr) << "err: could not parse a executable name from img_comp_cmd: " << shared->compCmd << Qt::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto snapArgsA = buildSnapArgs(clips[clips.size() - 2], imgAPath);
|
||||
auto snapArgsB = buildSnapArgs(clips[clips.size() - 1], imgAPath);
|
||||
auto compArgs = buildArgs(imgAPath, imgBPath);
|
||||
QProcess::execute("ffmpeg", snapArgsA);
|
||||
QProcess::execute("ffmpeg", snapArgsB);
|
||||
|
||||
if (compArgs.isEmpty())
|
||||
if (QFile::exists(imgAPath) && QFile::exists(imgBPath))
|
||||
{
|
||||
QTextStream(stderr) << "err: could not parse a executable name from img_comp_cmd: " << shared->compCmd << Qt::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
QProcess snapFromVidA;
|
||||
QProcess snapFromVidB;
|
||||
QProcess extComp;
|
||||
|
||||
snapFromVidA.start("ffmpeg", snapArgsA);
|
||||
snapFromVidA.waitForFinished();
|
||||
|
||||
snapFromVidB.start("ffmpeg", snapArgsB);
|
||||
snapFromVidB.waitForFinished();
|
||||
|
||||
extComp.start(compArgs[0], compArgs.mid(1));
|
||||
extComp.waitForFinished();
|
||||
|
||||
float score = 0;
|
||||
auto ok = true;
|
||||
|
||||
if (shared->outputType == "stdout")
|
||||
{
|
||||
score = getFloatFromExe(extComp.readAllStandardOutput());
|
||||
}
|
||||
else if (shared->outputType == "stderr")
|
||||
else
|
||||
{
|
||||
score = getFloatFromExe(extComp.readAllStandardError());
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
QTextStream(stderr) << "err: img_comp_out: " << shared->outputType << " is not valid. it must be 'stdout' or 'stderr'" << Qt::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
QTextStream(stdout) << compArgs.join(" ") << " --result: " << QString::number(score) << Qt::endl;
|
||||
QTextStream(stdout) << compArgs.join(" ") << " --result: " << QString::number(score) << Qt::endl;
|
||||
|
||||
if (score >= shared->imgThresh)
|
||||
if (eventQue.inQue)
|
||||
{
|
||||
if (eventQue.score < score)
|
||||
{
|
||||
QTextStream(stdout) << "--threshold_breached: " << QString::number(shared->imgThresh) << Qt::endl;
|
||||
|
||||
evt_t event;
|
||||
|
||||
event.timeStamp = curDT;
|
||||
event.score = score;
|
||||
event.imgPath = imgBPath;
|
||||
event.queAge = 0;
|
||||
|
||||
mod = true;
|
||||
|
||||
shared->recList.append(event);
|
||||
eventQue.score = score;
|
||||
eventQue.imgPath = imgBPath;
|
||||
}
|
||||
|
||||
eventQue.vidList.append(vidAPath);
|
||||
eventQue.vidList.append(vidBPath);
|
||||
|
||||
if (eventQue.queAge >= shared->evMaxSecs)
|
||||
{
|
||||
eventQue.inQue = false;
|
||||
|
||||
shared->recList.append(eventQue);
|
||||
|
||||
eventQue.imgPath.clear();
|
||||
eventQue.vidList.clear();
|
||||
eventQue.timeStamp.clear();
|
||||
|
||||
eventQue.score = 0;
|
||||
eventQue.queAge = 0;
|
||||
}
|
||||
}
|
||||
else if (score >= shared->imgThresh)
|
||||
{
|
||||
QTextStream(stdout) << "--threshold_breached: " << QString::number(shared->imgThresh) << Qt::endl;
|
||||
|
||||
eventQue.score = score;
|
||||
eventQue.imgPath = imgBPath;
|
||||
eventQue.inQue = true;
|
||||
eventQue.queAge = 0;
|
||||
eventQue.timeStamp = QDateTime::currentDateTime().toString(DATETIME_FMT);
|
||||
|
||||
eventQue.vidList.clear();
|
||||
eventQue.vidList.append(vidAPath);
|
||||
eventQue.vidList.append(vidBPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
23
src/camera.h
23
src/camera.h
|
@ -55,30 +55,13 @@ public:
|
|||
virtual bool exec();
|
||||
};
|
||||
|
||||
class Upkeep : public Loop
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit Upkeep(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
||||
|
||||
bool exec();
|
||||
};
|
||||
|
||||
class EventLoop : public Loop
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
||||
QStringList vidList;
|
||||
QString imgPath;
|
||||
QString name;
|
||||
float highScore;
|
||||
uint cycles;
|
||||
|
||||
bool wrOutVod();
|
||||
bool wrOutVod(const evt_t &event);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -94,9 +77,7 @@ class DetectLoop : public Loop
|
|||
private:
|
||||
|
||||
QTimer *pcTimer;
|
||||
uint delayCycles;
|
||||
bool mod;
|
||||
quint64 seed;
|
||||
evt_t eventQue;
|
||||
|
||||
void resetTimers();
|
||||
float getFloatFromExe(const QByteArray &line);
|
||||
|
|
|
@ -129,7 +129,7 @@ void enforceMaxImages(shared_t *share)
|
|||
{
|
||||
auto names = lsFilesInDir(share->buffPath + "/img", ".bmp");
|
||||
|
||||
while (names.size() > MAX_IMAGES)
|
||||
while (names.size() > (share->liveSecs / 2))
|
||||
{
|
||||
QFile::remove(share->buffPath + "/img/" + names[0]);
|
||||
|
||||
|
@ -137,11 +137,11 @@ void enforceMaxImages(shared_t *share)
|
|||
}
|
||||
}
|
||||
|
||||
void enforceMaxVids(shared_t *share)
|
||||
void enforceMaxClips(shared_t *share)
|
||||
{
|
||||
auto names = lsFilesInDir(share->buffPath + "/live", share->streamExt);
|
||||
|
||||
while (names.size() > MAX_VIDEOS)
|
||||
while (names.size() > (share->liveSecs / 2))
|
||||
{
|
||||
QFile::remove(share->buffPath + "/live/" + names[0]);
|
||||
|
||||
|
@ -217,8 +217,7 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
|
||||
share->retCode = 0;
|
||||
share->imgThresh = 8000;
|
||||
share->maxEvents = 100;
|
||||
share->maxLogSize = 100000;
|
||||
share->maxEvents = 30;
|
||||
share->skipCmd = false;
|
||||
share->postSecs = 60;
|
||||
share->evMaxSecs = 30;
|
||||
|
@ -226,12 +225,13 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
share->outputType = "stderr";
|
||||
share->compCmd = "magick compare -metric FUZZ " + QString(PREV_IMG) + " " + QString(NEXT_IMG) + " /dev/null";
|
||||
share->streamCodec = "copy";
|
||||
share->streamExt = ".ts";
|
||||
share->recExt = ".mp4";
|
||||
share->streamExt = ".avi";
|
||||
share->recExt = ".avi";
|
||||
share->thumbExt = ".jpg";
|
||||
share->imgThreads = thrCount;
|
||||
share->recThreads = thrCount;
|
||||
share->recFps = 30;
|
||||
share->liveSecs = 80;
|
||||
share->recScale = "1280:720";
|
||||
share->imgScale = "320:240";
|
||||
share->servUser = APP_BIN;
|
||||
|
@ -253,7 +253,6 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
rdLine("post_cmd = ", line, &share->postCmd);
|
||||
rdLine("img_thresh = ", line, &share->imgThresh);
|
||||
rdLine("max_events = ", line, &share->maxEvents);
|
||||
rdLine("max_log_size = ", line, &share->maxLogSize);
|
||||
rdLine("img_comp_out = ", line, &share->outputType);
|
||||
rdLine("img_comp_cmd = ", line, &share->compCmd);
|
||||
rdLine("stream_codec = ", line, &share->streamCodec);
|
||||
|
@ -266,19 +265,25 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
rdLine("rec_scale = ", line, &share->recScale);
|
||||
rdLine("img_scale = ", line, &share->imgScale);
|
||||
rdLine("service_user = ", line, &share->servUser);
|
||||
rdLine("live_secs = ", line, &share->liveSecs);
|
||||
}
|
||||
|
||||
} while(!line.isEmpty());
|
||||
|
||||
if (share->camName.isEmpty())
|
||||
{
|
||||
share->camName = QFileInfo(share->conf).fileName();
|
||||
share->camName = QFileInfo(share->conf).baseName();
|
||||
}
|
||||
|
||||
extCorrection(share->streamExt);
|
||||
extCorrection(share->recExt);
|
||||
extCorrection(share->thumbExt);
|
||||
|
||||
if (share->outputType != "stdout" && share->outputType != "stderr")
|
||||
{
|
||||
share->outputType = "stderr";
|
||||
}
|
||||
|
||||
if (share->buffPath.isEmpty())
|
||||
{
|
||||
share->buffPath = "/var/buffer/" + share->camName;
|
||||
|
@ -297,6 +302,16 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
share->recPath = QDir::cleanPath(share->recPath);
|
||||
}
|
||||
|
||||
if (share->liveSecs < 10)
|
||||
{
|
||||
share->liveSecs = 10;
|
||||
}
|
||||
|
||||
if ((share->liveSecs - 4) < share->evMaxSecs)
|
||||
{
|
||||
share->evMaxSecs = share->liveSecs - 4;
|
||||
}
|
||||
|
||||
share->retCode = EACCES;
|
||||
|
||||
if (!mkPath(share->recPath))
|
||||
|
|
29
src/common.h
29
src/common.h
|
@ -29,42 +29,34 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#define APP_VER "3.3.t3"
|
||||
#define APP_VER "3.3.t4"
|
||||
#define APP_NAME "Motion Watch"
|
||||
#define APP_BIN "mow"
|
||||
#define REC_LOG_NAME "rec.log"
|
||||
#define DET_LOG_NAME "det.log"
|
||||
#define UPK_LOG_NAME "upk.log"
|
||||
#define DATETIME_FMT "yyyyMMddhhmmss"
|
||||
#define STRFTIME_FMT "%Y%m%d%H%M%S"
|
||||
#define MAX_IMAGES 1000
|
||||
#define MAX_VIDEOS 1000
|
||||
#define PREV_IMG "&prev&"
|
||||
#define NEXT_IMG "&next&"
|
||||
|
||||
enum CmdExeType
|
||||
{
|
||||
MAIN_LOOP,
|
||||
VID_LOOP,
|
||||
IMG_LOOP
|
||||
VID_LOOP
|
||||
};
|
||||
|
||||
struct evt_t
|
||||
{
|
||||
QDateTime timeStamp;
|
||||
QString imgPath;
|
||||
float score;
|
||||
uint queAge;
|
||||
QList<QString> vidList;
|
||||
QString timeStamp;
|
||||
QString imgPath;
|
||||
float score;
|
||||
bool inQue;
|
||||
int queAge;
|
||||
};
|
||||
|
||||
struct shared_t
|
||||
{
|
||||
QList<evt_t> recList;
|
||||
QMutex recMutex;
|
||||
QMutex logMutex;
|
||||
QString conf;
|
||||
QString recLog;
|
||||
QString detLog;
|
||||
QString recordUri;
|
||||
QString buffPath;
|
||||
QString postCmd;
|
||||
|
@ -80,10 +72,10 @@ struct shared_t
|
|||
QString imgScale;
|
||||
QString servMainLoop;
|
||||
QString servVidLoop;
|
||||
QString servImgLoop;
|
||||
QString servUser;
|
||||
bool singleTenant;
|
||||
bool skipCmd;
|
||||
int liveSecs;
|
||||
int recFps;
|
||||
int imgThreads;
|
||||
int recThreads;
|
||||
|
@ -91,7 +83,6 @@ struct shared_t
|
|||
int postSecs;
|
||||
int imgThresh;
|
||||
int maxEvents;
|
||||
int maxLogSize;
|
||||
int retCode;
|
||||
};
|
||||
|
||||
|
@ -110,7 +101,7 @@ void rdLine(const QString ¶m, const QString &line, int *value);
|
|||
void rdLine(const QString ¶m, const QString &line, bool *value);
|
||||
void enforceMaxEvents(shared_t *share);
|
||||
void enforceMaxImages(shared_t *share);
|
||||
void enforceMaxVids(shared_t *share);
|
||||
void enforceMaxClips(shared_t *share);
|
||||
void extCorrection(QString &ext);
|
||||
|
||||
#endif // COMMON_H
|
||||
|
|
|
@ -23,6 +23,7 @@ void showHelp()
|
|||
QTextStream(stdout) << "-i : all valid config files found in /etc/mow will be used to create" << Qt::endl;
|
||||
QTextStream(stdout) << " a full instance; full meaning main and vid loop systemd services" << Qt::endl;
|
||||
QTextStream(stdout) << " will be created for each config file." << Qt::endl;
|
||||
QTextStream(stdout) << "-d : this is the same as -i except it will not auto start the services." << Qt::endl;
|
||||
QTextStream(stdout) << "-v : display the current version." << Qt::endl;
|
||||
QTextStream(stdout) << "-u : uninstall the entire app from your system, including all" << Qt::endl;
|
||||
QTextStream(stdout) << " systemd services related to it." << Qt::endl;
|
||||
|
|
|
@ -103,17 +103,21 @@ QString camCmdFromConf(shared_t *conf, CmdExeType type)
|
|||
}
|
||||
else
|
||||
{
|
||||
ret += "taskset -c " + buildThreadCount(conf->recThreads) + " ";
|
||||
ret += "ffmpeg -hide_banner -i '" + conf->recordUri + "' -strftime 1 -strftime_mkdir 1 ";
|
||||
ret += "ffmpeg -hide_banner -y -i '" + conf->recordUri + "' -strftime 1 -strftime_mkdir 1 ";
|
||||
|
||||
if (conf->recordUri.contains("rtsp"))
|
||||
{
|
||||
ret += "-rtsp_transport tcp ";
|
||||
}
|
||||
|
||||
ret += "-vf fps=" + QString::number(conf->recFps) + ",scale=" + conf->recScale + " ";
|
||||
ret += "-hls_segment_filename live/" + QString(STRFTIME_FMT) + conf->streamExt + " ";
|
||||
ret += "-y -vcodec " + conf->streamCodec + " -f hls -hls_time 2 -hls_list_size 1000 -hls_flags append_list+omit_endlist -t 60 stream.m3u8";
|
||||
if (conf->streamCodec != "copy")
|
||||
{
|
||||
ret += "-vf fps=" + QString::number(conf->recFps) + ",scale=" + conf->recScale + " ";
|
||||
}
|
||||
|
||||
ret += "-vcodec " + conf->streamCodec + " ";
|
||||
ret += "-reset_timestamps 1 -sc_threshold 0 -g 2 -force_key_frames \"expr:gte(t, n_forced * 2)\" -t 60 -segment_time 2 -f segment ";
|
||||
ret += conf->buffPath + "/live/" + QString(STRFTIME_FMT) + conf->streamExt;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -150,8 +154,8 @@ int rmService(const QString &servName)
|
|||
|
||||
if (QFile::exists(path))
|
||||
{
|
||||
ret = QProcess::execute("systemctl", {"stop", servName});
|
||||
ret = QProcess::execute("systemctl", {"disable", servName});
|
||||
if (ret == 0) ret = QProcess::execute("systemctl", {"stop", servName});
|
||||
if (ret == 0) ret = QProcess::execute("systemctl", {"disable", servName});
|
||||
|
||||
QFile::remove(path);
|
||||
QFile::remove("/usr/bin/" + servName);
|
||||
|
@ -168,6 +172,12 @@ int rmServiceByConf(const QString &confFile)
|
|||
{
|
||||
conf.retCode = rmService(conf.servMainLoop);
|
||||
conf.retCode = rmService(conf.servVidLoop);
|
||||
|
||||
QDir live(conf.buffPath + "/live");
|
||||
QDir img(conf.buffPath + "/img");
|
||||
|
||||
live.removeRecursively();
|
||||
img.removeRecursively();
|
||||
}
|
||||
|
||||
return conf.retCode;
|
||||
|
|
Loading…
Reference in New Issue
Block a user