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
115
src/camera.cpp
115
src/camera.cpp
|
@ -83,6 +83,8 @@ void Loop::init()
|
||||||
|
|
||||||
loopTimer->setSingleShot(false);
|
loopTimer->setSingleShot(false);
|
||||||
loopTimer->start(heartBeat * 1000);
|
loopTimer->start(heartBeat * 1000);
|
||||||
|
|
||||||
|
loopSlot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loop::loopSlot()
|
void Loop::loopSlot()
|
||||||
|
@ -105,8 +107,6 @@ bool Loop::exec()
|
||||||
|
|
||||||
RecLoop::RecLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
RecLoop::RecLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
||||||
{
|
{
|
||||||
once = true;
|
|
||||||
baseListRdy = false;
|
|
||||||
recProc = 0;
|
recProc = 0;
|
||||||
imgProc = 0;
|
imgProc = 0;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,8 @@ void RecLoop::init()
|
||||||
|
|
||||||
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &RecLoop::term);
|
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &RecLoop::term);
|
||||||
|
|
||||||
|
updateCmd();
|
||||||
|
|
||||||
Loop::init();
|
Loop::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,18 +133,23 @@ void RecLoop::updateCmd()
|
||||||
recArgs << "-strftime" << "1";
|
recArgs << "-strftime" << "1";
|
||||||
recArgs << "-strftime_mkdir" << "1";
|
recArgs << "-strftime_mkdir" << "1";
|
||||||
recArgs << "-hls_segment_filename" << "live/" + QString(STRFTIME_FMT) + ".ts";
|
recArgs << "-hls_segment_filename" << "live/" + QString(STRFTIME_FMT) + ".ts";
|
||||||
recArgs << "-hls_flags" << "delete_segments";
|
|
||||||
recArgs << "-y";
|
recArgs << "-y";
|
||||||
recArgs << "-vcodec" << "copy";
|
recArgs << "-vcodec" << "copy";
|
||||||
recArgs << "-f" << "hls";
|
recArgs << "-f" << "hls";
|
||||||
recArgs << "-hls_time" << "2";
|
recArgs << "-hls_time" << "2";
|
||||||
recArgs << "-hls_list_size" << "1000";
|
recArgs << "-hls_list_size" << "1000";
|
||||||
|
recArgs << "-hls_flags" << "append_list";
|
||||||
|
recArgs << "-rtsp_transport" << "tcp";
|
||||||
|
recArgs << "-stimeout" << "3000";
|
||||||
recArgs << "stream.m3u8";
|
recArgs << "stream.m3u8";
|
||||||
|
|
||||||
imgArgs << "-hide_banner";
|
imgArgs << "-hide_banner";
|
||||||
imgArgs << "-i" << shared->recordUrl;
|
imgArgs << "-i" << shared->recordUrl;
|
||||||
imgArgs << "-strftime" << "1";
|
imgArgs << "-strftime" << "1";
|
||||||
|
imgArgs << "-strftime_mkdir" << "1";
|
||||||
imgArgs << "-vf" << "fps=1,scale=320:240";
|
imgArgs << "-vf" << "fps=1,scale=320:240";
|
||||||
|
imgArgs << "-rtsp_transport" << "tcp";
|
||||||
|
imgArgs << "-stimeout" << "3000";
|
||||||
imgArgs << "img/" + QString(STRFTIME_FMT) + ".bmp";
|
imgArgs << "img/" + QString(STRFTIME_FMT) + ".bmp";
|
||||||
|
|
||||||
recProc->setProgram("ffmpeg");
|
recProc->setProgram("ffmpeg");
|
||||||
|
@ -151,10 +158,10 @@ void RecLoop::updateCmd()
|
||||||
imgProc->setProgram("ffmpeg");
|
imgProc->setProgram("ffmpeg");
|
||||||
imgProc->setArguments(imgArgs);
|
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);
|
curUrl = shared->recordUrl;
|
||||||
recLog("img_args_updated: " + imgArgs.join(" "), shared);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecLoop::term()
|
void RecLoop::term()
|
||||||
|
@ -170,12 +177,27 @@ void RecLoop::reset()
|
||||||
{
|
{
|
||||||
recLog("--rec_and_img_cmds_resetting--", shared);
|
recLog("--rec_and_img_cmds_resetting--", shared);
|
||||||
|
|
||||||
baseListRdy = false;
|
|
||||||
|
|
||||||
term();
|
term();
|
||||||
updateCmd();
|
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)
|
void RecLoop::startProc(const QString &desc, QProcess *proc)
|
||||||
{
|
{
|
||||||
if (proc->state() == QProcess::NotRunning)
|
if (proc->state() == QProcess::NotRunning)
|
||||||
|
@ -189,32 +211,17 @@ void RecLoop::startProc(const QString &desc, QProcess *proc)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
recLog(desc + "_cmd_start: fail", shared);
|
recLog(desc + "_cmd_start: fail", shared);
|
||||||
recLog(desc + "_cmd_stderr: " + QString(proc->readAllStandardError()), shared);
|
procError(desc, proc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecLoop::exec()
|
bool RecLoop::exec()
|
||||||
{
|
{
|
||||||
if (once)
|
procError("img", imgProc);
|
||||||
{
|
procError("rec", recProc);
|
||||||
updateCmd(); once = false;
|
|
||||||
}
|
if (curUrl != shared->recordUrl)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
recLog("a change in the recording URL was detected.", shared);
|
recLog("a change in the recording URL was detected.", shared);
|
||||||
reset();
|
reset();
|
||||||
|
@ -247,6 +254,7 @@ bool Upkeep::exec()
|
||||||
initLogFrontPages();
|
initLogFrontPages();
|
||||||
enforceMaxEvents(shared);
|
enforceMaxEvents(shared);
|
||||||
enforceMaxImages();
|
enforceMaxImages();
|
||||||
|
enforceMaxVids();
|
||||||
|
|
||||||
if (shared->evtHist.size() >= MAX_EVTHIST)
|
if (shared->evtHist.size() >= MAX_EVTHIST)
|
||||||
{
|
{
|
||||||
|
@ -263,27 +271,32 @@ bool Upkeep::exec()
|
||||||
|
|
||||||
EventLoop::EventLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
EventLoop::EventLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
||||||
{
|
{
|
||||||
heartBeat = 5;
|
heartBeat = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventLoop::exec()
|
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 event = shared->recList[0];
|
||||||
auto name = event.timeStamp.toString(DATETIME_FMT);
|
auto maxFiles = shared->evMaxSecs / 2;
|
||||||
auto maxFiles = shared->evMaxSecs / 2; //there's 2 secs in each hls segment
|
// there's 2 secs in each hls segment
|
||||||
auto vidList = backwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2);
|
|
||||||
|
|
||||||
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.removeLast();
|
|
||||||
|
|
||||||
vidList += forwardFacingFiles("live", ".ts", event.timeStamp, maxFiles / 2);
|
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)
|
for (auto &&hist : shared->evtHist)
|
||||||
{
|
{
|
||||||
|
@ -293,10 +306,13 @@ bool EventLoop::exec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vidList.isEmpty())
|
shared->recList.removeFirst();
|
||||||
{
|
}
|
||||||
shared->evtHist.append(vidList);
|
|
||||||
|
|
||||||
|
vidList.removeDuplicates();
|
||||||
|
|
||||||
|
if (!vidList.size() > 1)
|
||||||
|
{
|
||||||
recLog("attempting write out of event: " + name, shared);
|
recLog("attempting write out of event: " + name, shared);
|
||||||
|
|
||||||
if (wrOutVod(name, vidList))
|
if (wrOutVod(name, vidList))
|
||||||
|
@ -307,17 +323,13 @@ bool EventLoop::exec()
|
||||||
QStringList args;
|
QStringList args;
|
||||||
|
|
||||||
args << "convert";
|
args << "convert";
|
||||||
args << event.imgPath;
|
args << imgPath;
|
||||||
args << "events/" + name + ".jpg";
|
args << "events/" + name + ".jpg";
|
||||||
|
|
||||||
proc.start("magick", args);
|
proc.start("magick", args);
|
||||||
proc.waitForFinished();
|
proc.waitForFinished();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
shared->recList.removeFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Loop::exec();
|
return Loop::exec();
|
||||||
}
|
}
|
||||||
|
@ -389,9 +401,9 @@ DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loo
|
||||||
{
|
{
|
||||||
pcTimer = 0;
|
pcTimer = 0;
|
||||||
heartBeat = 2;
|
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
|
// actual start of DetectLoop by
|
||||||
// 8secs.
|
// 16secs.
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectLoop::init()
|
void DetectLoop::init()
|
||||||
|
@ -474,13 +486,16 @@ bool DetectLoop::exec()
|
||||||
|
|
||||||
detLog(extComp.program() + " " + args.join(" ") + " --result: " + output, shared);
|
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);
|
detLog("--threshold_breached: " + QString::number(shared->imgThresh), shared);
|
||||||
|
|
||||||
evt_t event;
|
evt_t event;
|
||||||
|
|
||||||
event.timeStamp = curDT;
|
event.timeStamp = curDT;
|
||||||
|
event.score = score;
|
||||||
event.imgPath = images[pos];
|
event.imgPath = images[pos];
|
||||||
|
|
||||||
shared->recList.append(event); mod = true;
|
shared->recList.append(event); mod = true;
|
||||||
|
|
|
@ -65,22 +65,16 @@ private:
|
||||||
|
|
||||||
QProcess *recProc;
|
QProcess *recProc;
|
||||||
QProcess *imgProc;
|
QProcess *imgProc;
|
||||||
QStringList recList;
|
|
||||||
QStringList imgList;
|
|
||||||
QString curUrl;
|
QString curUrl;
|
||||||
bool baseListRdy;
|
|
||||||
bool once;
|
|
||||||
|
|
||||||
void updateCmd();
|
void updateCmd();
|
||||||
void reset();
|
void reset();
|
||||||
void startProc(const QString &desc, QProcess *proc);
|
void startProc(const QString &desc, QProcess *proc);
|
||||||
|
void procError(const QString &desc, QProcess *proc);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
void term();
|
void term();
|
||||||
|
|
||||||
public:
|
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)
|
void rdLine(const QString ¶m, const QString &line, QString *value)
|
||||||
{
|
{
|
||||||
if (line.startsWith(param))
|
if (line.startsWith(param))
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define APP_VER "3.0.t12"
|
#define APP_VER "3.0.t13"
|
||||||
#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"
|
||||||
|
@ -37,12 +37,14 @@ using namespace std;
|
||||||
#define DATETIME_FMT "yyyyMMddhhmmss"
|
#define DATETIME_FMT "yyyyMMddhhmmss"
|
||||||
#define STRFTIME_FMT "%Y%m%d%H%M%S"
|
#define STRFTIME_FMT "%Y%m%d%H%M%S"
|
||||||
#define MAX_IMAGES 1000
|
#define MAX_IMAGES 1000
|
||||||
|
#define MAX_VIDEOS 1000
|
||||||
#define MAX_EVTHIST 100
|
#define MAX_EVTHIST 100
|
||||||
|
|
||||||
struct evt_t
|
struct evt_t
|
||||||
{
|
{
|
||||||
QDateTime timeStamp;
|
QDateTime timeStamp;
|
||||||
QString imgPath;
|
QString imgPath;
|
||||||
|
float score;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct shared_t
|
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 rdLine(const QString ¶m, const QString &line, int *value);
|
||||||
void enforceMaxEvents(shared_t *share);
|
void enforceMaxEvents(shared_t *share);
|
||||||
void enforceMaxImages();
|
void enforceMaxImages();
|
||||||
|
void enforceMaxVids();
|
||||||
|
|
||||||
class MultiInstance : public QObject
|
class MultiInstance : public QObject
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user