diff --git a/src/camera.cpp b/src/camera.cpp index 3e7dddc..026efbc 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -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; diff --git a/src/camera.h b/src/camera.h index 62febf7..3a9ed7e 100644 --- a/src/camera.h +++ b/src/camera.h @@ -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: diff --git a/src/common.cpp b/src/common.cpp index 87c6744..c57b72f 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -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 ¶m, const QString &line, QString *value) { if (line.startsWith(param)) diff --git a/src/common.h b/src/common.h index 74868f5..2cd1c6e 100644 --- a/src/common.h +++ b/src/common.h @@ -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 ¶m, const QString &line, QString *value); void rdLine(const QString ¶m, const QString &line, int *value); void enforceMaxEvents(shared_t *share); void enforceMaxImages(); +void enforceMaxVids(); class MultiInstance : public QObject {