v3.0.t2
Added the much need code in Camera object to actual start all of the threads. Added multi instance support via the -d option. Made the Loop object loop structure slot-signal compatible so all objects using it can interupt the main loop to run other slots.
This commit is contained in:
parent
b5ebbace12
commit
bbad30a5b0
|
@ -33,7 +33,7 @@ Camera::Camera(QObject *parent) : QObject(parent)
|
||||||
shared.webFont = "courier";
|
shared.webFont = "courier";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Camera::start(const QStringList &args)
|
int Camera::start(const QStringList &args)
|
||||||
{
|
{
|
||||||
auto ret = false;
|
auto ret = false;
|
||||||
|
|
||||||
|
@ -43,25 +43,55 @@ bool Camera::start(const QStringList &args)
|
||||||
{
|
{
|
||||||
QDir("live").removeRecursively();
|
QDir("live").removeRecursively();
|
||||||
|
|
||||||
|
auto thr1 = new QThread(QCoreApplication::instance());
|
||||||
|
auto thr2 = new QThread(QCoreApplication::instance());
|
||||||
|
auto thr3 = new QThread(QCoreApplication::instance());
|
||||||
|
auto thr4 = new QThread(QCoreApplication::instance());
|
||||||
|
|
||||||
|
new RecLoop(&shared, thr1, this);
|
||||||
|
new Upkeep(&shared, thr2, this);
|
||||||
|
new EventLoop(&shared, thr3, this);
|
||||||
|
new DetectLoop(&shared, thr4, this);
|
||||||
|
|
||||||
|
thr1->start();
|
||||||
|
thr2->start();
|
||||||
|
thr3->start();
|
||||||
|
thr4->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return shared.retCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loop::Loop(shared_t *sharedRes, QObject *parent) : QObject(parent)
|
Loop::Loop(shared_t *sharedRes, QThread *thr, QObject *parent) : QObject(0)
|
||||||
{
|
{
|
||||||
shared = sharedRes;
|
shared = sharedRes;
|
||||||
heartBeat = 10;
|
heartBeat = 10;
|
||||||
|
|
||||||
|
connect(this, &Loop::loopSig, this, &Loop::loopSlot);
|
||||||
|
connect(thr, &QThread::started, this, &Loop::init);
|
||||||
|
connect(parent, &QObject::destroyed, this, &Loop::deleteLater);
|
||||||
|
connect(parent, &QObject::destroyed, thr, &QThread::terminate);
|
||||||
|
|
||||||
|
moveToThread(thr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loop::loop()
|
void Loop::init()
|
||||||
{
|
{
|
||||||
while (exec())
|
emit loopSig();
|
||||||
{
|
}
|
||||||
|
|
||||||
|
void Loop::loopSlot()
|
||||||
|
{
|
||||||
|
auto ret = exec();
|
||||||
|
|
||||||
if (heartBeat != 0)
|
if (heartBeat != 0)
|
||||||
{
|
{
|
||||||
thread()->sleep(heartBeat);
|
thread()->sleep(heartBeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
emit loopSig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +100,7 @@ bool Loop::exec()
|
||||||
return shared->retCode == 0;
|
return shared->retCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecLoop::RecLoop(shared_t *sharedRes, QObject *parent) : Loop(sharedRes, parent)
|
RecLoop::RecLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
||||||
{
|
{
|
||||||
once = true;
|
once = true;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +125,8 @@ void RecLoop::updateCmd()
|
||||||
proc.setProgram("ffmpeg");
|
proc.setProgram("ffmpeg");
|
||||||
proc.setArguments(args);
|
proc.setArguments(args);
|
||||||
|
|
||||||
|
curUrl = shared->recordUrl;
|
||||||
|
|
||||||
recLog("rec_args_updated: " + args.join(" "), shared);
|
recLog("rec_args_updated: " + args.join(" "), shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,19 +142,18 @@ void RecLoop::reset()
|
||||||
|
|
||||||
bool RecLoop::exec()
|
bool RecLoop::exec()
|
||||||
{
|
{
|
||||||
auto args = proc.arguments();
|
|
||||||
auto md5 = genMD5(QString("stream.m3u8"));
|
auto md5 = genMD5(QString("stream.m3u8"));
|
||||||
|
|
||||||
if (once)
|
if (once)
|
||||||
{
|
{
|
||||||
updateCmd(); once = false; streamMD5 = genMD5(QByteArray("FIRST"));
|
updateCmd(); once = false; streamMD5 = genMD5(QByteArray("FIRST"));
|
||||||
}
|
}
|
||||||
else if ((args[3] != shared->recordUrl) || (streamMD5 == md5))
|
else if ((curUrl != shared->recordUrl) || (streamMD5 == md5))
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hashLogLine = "stream_hash prev:" + QString(streamMD5.toHex()) + " new:" + QString(md5.toHex());
|
auto hashLogLine = "stream_hash--prev:" + QString(streamMD5.toHex()) + "--new:" + QString(md5.toHex());
|
||||||
|
|
||||||
recLog(hashLogLine, shared);
|
recLog(hashLogLine, shared);
|
||||||
|
|
||||||
|
@ -144,7 +175,7 @@ bool RecLoop::exec()
|
||||||
return Loop::exec();
|
return Loop::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
Upkeep::Upkeep(shared_t *sharedRes, QObject *parent) : Loop(sharedRes, parent) {}
|
Upkeep::Upkeep(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent) {}
|
||||||
|
|
||||||
bool Upkeep::exec()
|
bool Upkeep::exec()
|
||||||
{
|
{
|
||||||
|
@ -193,7 +224,7 @@ bool Upkeep::exec()
|
||||||
return Loop::exec();
|
return Loop::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
EventLoop::EventLoop(shared_t *sharedRes, QObject *parent) : Loop(sharedRes, parent)
|
EventLoop::EventLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
||||||
{
|
{
|
||||||
heartBeat = 2;
|
heartBeat = 2;
|
||||||
}
|
}
|
||||||
|
@ -281,13 +312,18 @@ bool EventLoop::wrOutVod(const evt_t &event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DetectLoop::DetectLoop(shared_t *sharedRes, QObject *parent) : Loop(sharedRes, parent)
|
DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
|
||||||
{
|
{
|
||||||
heartBeat = 0;
|
heartBeat = 0;
|
||||||
evId = 0;
|
evId = 0;
|
||||||
pcId = 0;
|
pcId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
resetTimers();
|
void DetectLoop::init()
|
||||||
|
{
|
||||||
|
thread()->usleep(200);
|
||||||
|
|
||||||
|
resetTimers(); Loop::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectLoop::resetTimers()
|
void DetectLoop::resetTimers()
|
||||||
|
@ -326,7 +362,7 @@ void DetectLoop::timerEvent(QTimerEvent *event)
|
||||||
shared->maxScore = 0;
|
shared->maxScore = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->timerId() == pcId)
|
if ((event->timerId() == pcId) && (!shared->postCmd.isEmpty()))
|
||||||
{
|
{
|
||||||
detLog("---POST_BREAK---", shared);
|
detLog("---POST_BREAK---", shared);
|
||||||
|
|
||||||
|
|
63
src/camera.h
63
src/camera.h
|
@ -18,26 +18,6 @@
|
||||||
#include "web.h"
|
#include "web.h"
|
||||||
#include "mo_detect.h"
|
#include "mo_detect.h"
|
||||||
|
|
||||||
class Loop : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
shared_t *shared;
|
|
||||||
int heartBeat;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void loop();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit Loop(shared_t *shared, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
virtual bool exec();
|
|
||||||
};
|
|
||||||
|
|
||||||
class Camera : public QObject
|
class Camera : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -50,7 +30,35 @@ public:
|
||||||
|
|
||||||
explicit Camera(QObject *parent = nullptr);
|
explicit Camera(QObject *parent = nullptr);
|
||||||
|
|
||||||
bool start(const QStringList &args);
|
int start(const QStringList &args);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Loop : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
shared_t *shared;
|
||||||
|
int heartBeat;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
|
||||||
|
virtual void init();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void loopSlot();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void loopSig();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit Loop(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
virtual bool exec();
|
||||||
};
|
};
|
||||||
|
|
||||||
class RecLoop : public Loop
|
class RecLoop : public Loop
|
||||||
|
@ -60,6 +68,7 @@ class RecLoop : public Loop
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QProcess proc;
|
QProcess proc;
|
||||||
|
QString curUrl;
|
||||||
QByteArray streamMD5;
|
QByteArray streamMD5;
|
||||||
bool once;
|
bool once;
|
||||||
|
|
||||||
|
@ -68,7 +77,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit RecLoop(shared_t *shared, QObject *parent = nullptr);
|
explicit RecLoop(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
||||||
|
|
||||||
bool exec();
|
bool exec();
|
||||||
};
|
};
|
||||||
|
@ -79,7 +88,7 @@ class Upkeep : public Loop
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit Upkeep(shared_t *shared, QObject *parent = nullptr);
|
explicit Upkeep(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
||||||
|
|
||||||
bool exec();
|
bool exec();
|
||||||
};
|
};
|
||||||
|
@ -94,7 +103,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit EventLoop(shared_t *shared, QObject *parent = nullptr);
|
explicit EventLoop(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
||||||
|
|
||||||
bool exec();
|
bool exec();
|
||||||
};
|
};
|
||||||
|
@ -112,9 +121,13 @@ private:
|
||||||
void resetTimers();
|
void resetTimers();
|
||||||
void timerEvent(QTimerEvent *event);
|
void timerEvent(QTimerEvent *event);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit DetectLoop(shared_t *shared, QObject *parent = nullptr);
|
explicit DetectLoop(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
||||||
|
|
||||||
bool exec();
|
bool exec();
|
||||||
};
|
};
|
||||||
|
|
|
@ -190,7 +190,7 @@ bool rdConf(shared_t *share)
|
||||||
|
|
||||||
if (!QDir::setCurrent(share->outDir))
|
if (!QDir::setCurrent(share->outDir))
|
||||||
{
|
{
|
||||||
QTextStream(stderr) << "err: failed to change/create the current working directory to camera folder: '" << share->outDir << ".' does it exists?" << Qt::endl;
|
QTextStream(stderr) << "err: failed to change/create the current working directory to camera folder: '" << share->outDir << "' does it exists?" << Qt::endl;
|
||||||
|
|
||||||
share->retCode = ENOENT;
|
share->retCode = ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -198,3 +198,78 @@ bool rdConf(shared_t *share)
|
||||||
|
|
||||||
return share->retCode == 0;
|
return share->retCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MultiInstance::MultiInstance(QObject *parent) : QObject(parent) {}
|
||||||
|
|
||||||
|
void MultiInstance::instStdout()
|
||||||
|
{
|
||||||
|
for (auto &&proc : procList)
|
||||||
|
{
|
||||||
|
QTextStream(stdout) << proc->readAllStandardOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiInstance::instStderr()
|
||||||
|
{
|
||||||
|
for (auto &&proc : procList)
|
||||||
|
{
|
||||||
|
QTextStream(stderr) << proc->readAllStandardError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiInstance::procFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
Q_UNUSED(exitCode)
|
||||||
|
Q_UNUSED(exitStatus)
|
||||||
|
|
||||||
|
for (auto &&proc : procList)
|
||||||
|
{
|
||||||
|
if (proc->state() == QProcess::Running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreApplication::quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MultiInstance::start(const QStringList &args)
|
||||||
|
{
|
||||||
|
auto ret = ENOENT;
|
||||||
|
auto path = getParam("-d", args);
|
||||||
|
auto files = lsFilesInDir(path);
|
||||||
|
|
||||||
|
if (!QDir(path).exists())
|
||||||
|
{
|
||||||
|
QTextStream(stderr) << "err: the supplied directory in -d '" << path << "' does not exists or is not a directory.";
|
||||||
|
}
|
||||||
|
else if (files.isEmpty())
|
||||||
|
{
|
||||||
|
QTextStream(stderr) << "err: no config files found in '" << path << "'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto &&conf : files)
|
||||||
|
{
|
||||||
|
auto proc = new QProcess(this);
|
||||||
|
|
||||||
|
QStringList subArgs;
|
||||||
|
|
||||||
|
subArgs << "-c" << conf;
|
||||||
|
|
||||||
|
connect(proc, &QProcess::readyReadStandardOutput, this, &MultiInstance::instStdout);
|
||||||
|
connect(proc, &QProcess::readyReadStandardError, this, &MultiInstance::instStderr);
|
||||||
|
connect(proc, &QProcess::finished, this, &MultiInstance::procFinished);
|
||||||
|
|
||||||
|
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, proc, &QProcess::terminate);
|
||||||
|
|
||||||
|
proc->setProgram(APP_BIN);
|
||||||
|
proc->setArguments(subArgs);
|
||||||
|
proc->start();
|
||||||
|
|
||||||
|
procList.append(proc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
24
src/common.h
24
src/common.h
|
@ -30,8 +30,9 @@
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define APP_VER "3.0.t1"
|
#define APP_VER "3.0.t2"
|
||||||
#define APP_NAME "Motion Watch"
|
#define APP_NAME "Motion Watch"
|
||||||
|
#define APP_BIN "mow"
|
||||||
#define REC_LOG_NAME "rec_log_lines.html"
|
#define REC_LOG_NAME "rec_log_lines.html"
|
||||||
#define DET_LOG_NAME "det_log_lines.html"
|
#define DET_LOG_NAME "det_log_lines.html"
|
||||||
#define UPK_LOG_NAME "upk_log_lines.html"
|
#define UPK_LOG_NAME "upk_log_lines.html"
|
||||||
|
@ -86,4 +87,25 @@ 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);
|
||||||
|
|
||||||
|
class MultiInstance : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QList<QProcess*> procList;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void instStdout();
|
||||||
|
void instStderr();
|
||||||
|
void procFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit MultiInstance(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int start(const QStringList &args);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // COMMON_H
|
#endif // COMMON_H
|
||||||
|
|
24
src/main.cpp
24
src/main.cpp
|
@ -10,9 +10,7 @@
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
#include "mo_detect.h"
|
#include "common.h"
|
||||||
#include "logger.h"
|
|
||||||
#include "web.h"
|
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
|
@ -30,18 +28,34 @@ int main(int argc, char** argv)
|
||||||
QTextStream(stdout) << "Motion Watch " << APP_VER << Qt::endl << Qt::endl;
|
QTextStream(stdout) << "Motion Watch " << APP_VER << Qt::endl << Qt::endl;
|
||||||
QTextStream(stdout) << "Usage: mow <argument>" << Qt::endl << Qt::endl;
|
QTextStream(stdout) << "Usage: mow <argument>" << Qt::endl << Qt::endl;
|
||||||
QTextStream(stdout) << "-h : display usage information about this application." << Qt::endl;
|
QTextStream(stdout) << "-h : display usage information about this application." << Qt::endl;
|
||||||
QTextStream(stdout) << "-c : path to the config file." << Qt::endl;
|
QTextStream(stdout) << "-c : path to the config file used to run a single camera instance." << Qt::endl;
|
||||||
|
QTextStream(stdout) << "-d : path to a directory that can contain multiple config files." << Qt::endl;
|
||||||
|
QTextStream(stdout) << " each file found in the directory will be used to run a" << Qt::endl;
|
||||||
|
QTextStream(stdout) << " camera instance." << Qt::endl;
|
||||||
QTextStream(stdout) << "-v : display the current version." << Qt::endl << Qt::endl;
|
QTextStream(stdout) << "-v : display the current version." << Qt::endl << Qt::endl;
|
||||||
}
|
}
|
||||||
else if (args.contains("-v"))
|
else if (args.contains("-v"))
|
||||||
{
|
{
|
||||||
QTextStream(stdout) << APP_VER << Qt::endl;
|
QTextStream(stdout) << APP_VER << Qt::endl;
|
||||||
}
|
}
|
||||||
|
else if (args.contains("-d"))
|
||||||
|
{
|
||||||
|
auto *muli = new MultiInstance(&app);
|
||||||
|
|
||||||
|
ret = muli->start(args);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
ret = QCoreApplication::exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (args.contains("-c"))
|
else if (args.contains("-c"))
|
||||||
{
|
{
|
||||||
auto *cam = new Camera(&app);
|
auto *cam = new Camera(&app);
|
||||||
|
|
||||||
if (cam->start(args))
|
ret = cam->start(args);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
ret = QCoreApplication::exec();
|
ret = QCoreApplication::exec();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user