v3.0.t13
-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:
parent
16312a93f5
commit
4b4c2649b8
161
src/camera.cpp
161
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;
|
||||
|
|
14
src/camera.h
14
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:
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user