-removed use of evtHist. will instead allow eventLoop to que up
 duplicate live video clips and then remove later using
 QStringList::removeDuplicates().

-changed up the ffmpeg commands to utilize tcp and re-added a tcp
 timeout argument, removing the need for command stall checking.

-added logic to pick the snapshot with the highest diff score as
 the event thumbnail.
This commit is contained in:
Zii 2023-06-09 16:24:32 -04:00
parent 16312a93f5
commit 4b4c2649b8
4 changed files with 108 additions and 84 deletions

View File

@ -83,6 +83,8 @@ void Loop::init()
loopTimer->setSingleShot(false);
loopTimer->start(heartBeat * 1000);
loopSlot();
}
void Loop::loopSlot()
@ -105,10 +107,8 @@ bool Loop::exec()
RecLoop::RecLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
{
once = true;
baseListRdy = false;
recProc = 0;
imgProc = 0;
recProc = 0;
imgProc = 0;
}
void RecLoop::init()
@ -118,6 +118,8 @@ void RecLoop::init()
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &RecLoop::term);
updateCmd();
Loop::init();
}
@ -131,18 +133,23 @@ void RecLoop::updateCmd()
recArgs << "-strftime" << "1";
recArgs << "-strftime_mkdir" << "1";
recArgs << "-hls_segment_filename" << "live/" + QString(STRFTIME_FMT) + ".ts";
recArgs << "-hls_flags" << "delete_segments";
recArgs << "-y";
recArgs << "-vcodec" << "copy";
recArgs << "-f" << "hls";
recArgs << "-hls_time" << "2";
recArgs << "-hls_list_size" << "1000";
recArgs << "-hls_flags" << "append_list";
recArgs << "-rtsp_transport" << "tcp";
recArgs << "-stimeout" << "3000";
recArgs << "stream.m3u8";
imgArgs << "-hide_banner";
imgArgs << "-i" << shared->recordUrl;
imgArgs << "-strftime" << "1";
imgArgs << "-strftime_mkdir" << "1";
imgArgs << "-vf" << "fps=1,scale=320:240";
imgArgs << "-rtsp_transport" << "tcp";
imgArgs << "-stimeout" << "3000";
imgArgs << "img/" + QString(STRFTIME_FMT) + ".bmp";
recProc->setProgram("ffmpeg");
@ -151,10 +158,10 @@ void RecLoop::updateCmd()
imgProc->setProgram("ffmpeg");
imgProc->setArguments(imgArgs);
curUrl = shared->recordUrl;
recLog("rec_args: " + recArgs.join(" "), shared);
recLog("img_args: " + imgArgs.join(" "), shared);
recLog("rec_args_updated: " + recArgs.join(" "), shared);
recLog("img_args_updated: " + imgArgs.join(" "), shared);
curUrl = shared->recordUrl;
}
void RecLoop::term()
@ -170,12 +177,27 @@ void RecLoop::reset()
{
recLog("--rec_and_img_cmds_resetting--", shared);
baseListRdy = false;
term();
updateCmd();
}
void RecLoop::procError(const QString &desc, QProcess *proc)
{
if (proc->isOpen() && proc->state() == QProcess::NotRunning)
{
auto errBlob = QString(proc->readAllStandardError());
auto errLines = errBlob.split('\n');
if (!errLines.isEmpty())
{
for (auto &&line : errLines)
{
recLog(desc + "_cmd_stderr: " + line, shared);
}
}
}
}
void RecLoop::startProc(const QString &desc, QProcess *proc)
{
if (proc->state() == QProcess::NotRunning)
@ -189,32 +211,17 @@ void RecLoop::startProc(const QString &desc, QProcess *proc)
else
{
recLog(desc + "_cmd_start: fail", shared);
recLog(desc + "_cmd_stderr: " + QString(proc->readAllStandardError()), shared);
procError(desc, proc);
}
}
}
bool RecLoop::exec()
{
if (once)
{
updateCmd(); once = false;
}
else if (!baseListRdy)
{
baseListRdy = true;
}
else if (backwardFacingFiles("live", ".ts", QDateTime::currentDateTime(), heartBeat).isEmpty())
{
recLog("backward facing files in the live stream are empty. cmd stall is suspected.", shared);
reset();
}
else if (backwardFacingFiles("img", ".bmp", QDateTime::currentDateTime(), heartBeat).isEmpty())
{
recLog("backward facing files in the image stream are empty. cmd stall is suspected.", shared);
reset();
}
else if (curUrl != shared->recordUrl)
procError("img", imgProc);
procError("rec", recProc);
if (curUrl != shared->recordUrl)
{
recLog("a change in the recording URL was detected.", shared);
reset();
@ -247,6 +254,7 @@ bool Upkeep::exec()
initLogFrontPages();
enforceMaxEvents(shared);
enforceMaxImages();
enforceMaxVids();
if (shared->evtHist.size() >= MAX_EVTHIST)
{
@ -263,62 +271,66 @@ bool Upkeep::exec()
EventLoop::EventLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
{
heartBeat = 5;
heartBeat = 2;
}
bool EventLoop::exec()
{
if (!shared->recList.isEmpty())
{
QStringList vidList;
QString imgPath;
QString name;
float highScore = 0;
while (!shared->recList.isEmpty())
{
auto event = shared->recList[0];
auto name = event.timeStamp.toString(DATETIME_FMT);
auto maxFiles = shared->evMaxSecs / 2; //there's 2 secs in each hls segment
auto vidList = backwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2);
auto maxFiles = shared->evMaxSecs / 2;
// there's 2 secs in each hls segment
if (vidList.isEmpty())
if (highScore < event.score)
{
recLog("err: no backward faces files were found for event: " + name, shared);
name = event.timeStamp.toString(DATETIME_FMT);
imgPath = event.imgPath;
highScore = event.score;
}
else
vidList.append(backwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2));
vidList.removeLast();
vidList.append(forwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2));
for (auto &&hist : shared->evtHist)
{
vidList.removeLast();
vidList += forwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2);
for (auto &&hist : shared->evtHist)
if (vidList.contains(hist))
{
if (vidList.contains(hist))
{
vidList.removeAll(hist);
}
}
if (!vidList.isEmpty())
{
shared->evtHist.append(vidList);
recLog("attempting write out of event: " + name, shared);
if (wrOutVod(name, vidList))
{
genHTMLvod(name);
QProcess proc;
QStringList args;
args << "convert";
args << event.imgPath;
args << "events/" + name + ".jpg";
proc.start("magick", args);
proc.waitForFinished();
}
vidList.removeAll(hist);
}
}
shared->recList.removeFirst();
}
vidList.removeDuplicates();
if (!vidList.size() > 1)
{
recLog("attempting write out of event: " + name, shared);
if (wrOutVod(name, vidList))
{
genHTMLvod(name);
QProcess proc;
QStringList args;
args << "convert";
args << imgPath;
args << "events/" + name + ".jpg";
proc.start("magick", args);
proc.waitForFinished();
}
}
return Loop::exec();
}
@ -389,9 +401,9 @@ DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loo
{
pcTimer = 0;
heartBeat = 2;
delayCycles = 4; // this will be used to delay the
delayCycles = 8; // this will be used to delay the
// actual start of DetectLoop by
// 8secs.
// 16secs.
}
void DetectLoop::init()
@ -474,13 +486,16 @@ bool DetectLoop::exec()
detLog(extComp.program() + " " + args.join(" ") + " --result: " + output, shared);
if (output.toFloat() >= shared->imgThresh)
auto score = output.toFloat();
if (score >= shared->imgThresh)
{
detLog("--threshold_breached: " + QString::number(shared->imgThresh), shared);
evt_t event;
event.timeStamp = curDT;
event.score = score;
event.imgPath = images[pos];
shared->recList.append(event); mod = true;

View File

@ -63,24 +63,18 @@ class RecLoop : public Loop
private:
QProcess *recProc;
QProcess *imgProc;
QStringList recList;
QStringList imgList;
QString curUrl;
bool baseListRdy;
bool once;
QProcess *recProc;
QProcess *imgProc;
QString curUrl;
void updateCmd();
void reset();
void startProc(const QString &desc, QProcess *proc);
void procError(const QString &desc, QProcess *proc);
private slots:
void init();
public slots:
void term();
public:

View File

@ -139,6 +139,18 @@ void enforceMaxImages()
}
}
void enforceMaxVids()
{
auto names = lsFilesInDir("live", ".ts");
while (names.size() > MAX_VIDEOS)
{
QFile::remove("live/" + names[0]);
names.removeFirst();
}
}
void rdLine(const QString &param, const QString &line, QString *value)
{
if (line.startsWith(param))

View File

@ -28,7 +28,7 @@
using namespace std;
#define APP_VER "3.0.t12"
#define APP_VER "3.0.t13"
#define APP_NAME "Motion Watch"
#define APP_BIN "mow"
#define REC_LOG_NAME "rec_log_lines.html"
@ -37,12 +37,14 @@ using namespace std;
#define DATETIME_FMT "yyyyMMddhhmmss"
#define STRFTIME_FMT "%Y%m%d%H%M%S"
#define MAX_IMAGES 1000
#define MAX_VIDEOS 1000
#define MAX_EVTHIST 100
struct evt_t
{
QDateTime timeStamp;
QString imgPath;
float score;
};
struct shared_t
@ -81,6 +83,7 @@ void rdLine(const QString &param, const QString &line, QString *value);
void rdLine(const QString &param, const QString &line, int *value);
void enforceMaxEvents(shared_t *share);
void enforceMaxImages();
void enforceMaxVids();
class MultiInstance : public QObject
{