v3.6.t1
-all recordings, clips and snapshots are now base on UTC naming scheme for easy name prediction for client apps. -detect loop no longer list dirs for files or monitors for dir changes. it will now predict video clip names base on current UTC time.
This commit is contained in:
parent
c103ee3c47
commit
88ea1086f6
|
@ -92,7 +92,7 @@ void enforceMaxImages(shared_t *share)
|
||||||
{
|
{
|
||||||
auto names = lsFilesInDir(share->buffPath + "/img", ".bmp");
|
auto names = lsFilesInDir(share->buffPath + "/img", ".bmp");
|
||||||
|
|
||||||
while (names.size() > (share->liveSecs / 2))
|
while (names.size() > MAX_IMAGES)
|
||||||
{
|
{
|
||||||
QFile::remove(share->buffPath + "/img/" + names[0]);
|
QFile::remove(share->buffPath + "/img/" + names[0]);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ void enforceMaxClips(shared_t *share)
|
||||||
{
|
{
|
||||||
auto names = lsFilesInDir(share->buffPath + "/live", share->streamExt);
|
auto names = lsFilesInDir(share->buffPath + "/live", share->streamExt);
|
||||||
|
|
||||||
while (names.size() > (share->liveSecs / 2))
|
while (names.size() > (share->liveSecs / SEG_SIZE))
|
||||||
{
|
{
|
||||||
QFile::remove(share->buffPath + "/live/" + names[0]);
|
QFile::remove(share->buffPath + "/live/" + names[0]);
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,15 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define APP_VERSION "3.5"
|
#define APP_VERSION "3.6.t1"
|
||||||
#define APP_NAME "JustMotion"
|
#define APP_NAME "JustMotion"
|
||||||
#define APP_TARGET "jmotion"
|
#define APP_TARGET "jmotion"
|
||||||
#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 PREV_IMG "&prev&"
|
#define PREV_IMG "&prev&"
|
||||||
#define NEXT_IMG "&next&"
|
#define NEXT_IMG "&next&"
|
||||||
|
#define SEG_SIZE 10
|
||||||
|
#define MAX_IMAGES 100
|
||||||
|
|
||||||
enum CmdExeType
|
enum CmdExeType
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include "detect_loop.h"
|
#include "detect_loop.h"
|
||||||
|
|
||||||
DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : QFileSystemWatcher(parent)
|
DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
pcTimer = 0;
|
pcTimer = 0;
|
||||||
shared = sharedRes;
|
shared = sharedRes;
|
||||||
|
@ -26,14 +26,21 @@ DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : QFi
|
||||||
void DetectLoop::init()
|
void DetectLoop::init()
|
||||||
{
|
{
|
||||||
pcTimer = new QTimer(this);
|
pcTimer = new QTimer(this);
|
||||||
|
evTimer = new QTimer(this);
|
||||||
|
dTime = QDateTime::currentDateTimeUtc();
|
||||||
|
|
||||||
connect(pcTimer, &QTimer::timeout, this, &DetectLoop::pcBreak);
|
connect(pcTimer, &QTimer::timeout, this, &DetectLoop::pcBreak);
|
||||||
connect(this, &QFileSystemWatcher::directoryChanged, this, &DetectLoop::updated);
|
connect(evTimer, &QTimer::timeout, this, &DetectLoop::evBreak);
|
||||||
|
connect(this, &DetectLoop::loop, this, &DetectLoop::exec);
|
||||||
|
|
||||||
pcTimer->start(shared->postSecs * 1000);
|
pcTimer->start(shared->postSecs * 1000);
|
||||||
|
evTimer->start(shared->evMaxSecs * 1000);
|
||||||
|
|
||||||
setupBuffDir(shared->buffPath);
|
setupBuffDir(shared->buffPath);
|
||||||
addPath(shared->buffPath + "/live");
|
|
||||||
|
eTimer.start();
|
||||||
|
|
||||||
|
QTimer::singleShot(SEG_SIZE + 4, this, &DetectLoop::exec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectLoop::reset()
|
void DetectLoop::reset()
|
||||||
|
@ -47,29 +54,6 @@ void DetectLoop::reset()
|
||||||
eventQue.timeStamp.clear();
|
eventQue.timeStamp.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectLoop::updated(const QString &path)
|
|
||||||
{
|
|
||||||
eTimer.start();
|
|
||||||
|
|
||||||
auto clips = lsFilesInDir(path, shared->streamExt);
|
|
||||||
auto index = clips.indexOf(vidBName);
|
|
||||||
|
|
||||||
if (clips.size() - (index + 1) < 3)
|
|
||||||
{
|
|
||||||
thread()->sleep(1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vidAName = clips[clips.size() - 3];
|
|
||||||
vidBName = clips[clips.size() - 2];
|
|
||||||
|
|
||||||
vidAPath = shared->buffPath + "/live/" + vidAName;
|
|
||||||
vidBPath = shared->buffPath + "/live/" + vidBName;
|
|
||||||
|
|
||||||
exec(); thread()->sleep(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DetectLoop::pcBreak()
|
void DetectLoop::pcBreak()
|
||||||
{
|
{
|
||||||
prevClips.clear();
|
prevClips.clear();
|
||||||
|
@ -100,6 +84,16 @@ void DetectLoop::pcBreak()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DetectLoop::evBreak()
|
||||||
|
{
|
||||||
|
if (eventQue.inQue)
|
||||||
|
{
|
||||||
|
shared->recList.append(eventQue);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float DetectLoop::getFloatFromExe(const QByteArray &line)
|
float DetectLoop::getFloatFromExe(const QByteArray &line)
|
||||||
{
|
{
|
||||||
QString strLine(line);
|
QString strLine(line);
|
||||||
|
@ -142,26 +136,9 @@ QStringList DetectLoop::buildArgs(const QString &prev, const QString &next)
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList DetectLoop::buildSnapArgs(const QString &vidSrc, const QString &imgPath)
|
|
||||||
{
|
|
||||||
QStringList ret;
|
|
||||||
|
|
||||||
ret.append("-hide_banner");
|
|
||||||
ret.append("-loglevel");
|
|
||||||
ret.append("panic");
|
|
||||||
ret.append("-y");
|
|
||||||
ret.append("-i");
|
|
||||||
ret.append(vidSrc);
|
|
||||||
ret.append("-frames:v");
|
|
||||||
ret.append("1");
|
|
||||||
ret.append(imgPath);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString DetectLoop::statusLine()
|
QString DetectLoop::statusLine()
|
||||||
{
|
{
|
||||||
if (eTimer.elapsed() >= 5000)
|
if (eTimer.elapsed() >= 30000)
|
||||||
{
|
{
|
||||||
emit starving();
|
emit starving();
|
||||||
|
|
||||||
|
@ -175,79 +152,111 @@ QString DetectLoop::statusLine()
|
||||||
|
|
||||||
void DetectLoop::exec()
|
void DetectLoop::exec()
|
||||||
{
|
{
|
||||||
auto imgAPath = shared->buffPath + "/img/" + QFileInfo(vidAPath).baseName() + ".bmp";
|
auto vidPath = shared->buffPath + "/live/" + dTime.toString(DATETIME_FMT) + shared->streamExt;
|
||||||
auto imgBPath = shared->buffPath + "/img/" + QFileInfo(vidBPath).baseName() + ".bmp";
|
auto found = false;
|
||||||
auto snapArgsA = buildSnapArgs(vidAPath, imgAPath);
|
|
||||||
auto snapArgsB = buildSnapArgs(vidBPath, imgBPath);
|
|
||||||
auto compArgs = buildArgs(imgAPath, imgBPath);
|
|
||||||
|
|
||||||
if (compArgs.isEmpty())
|
for (auto i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
qCritical() << "err: could not parse a executable name from img_comp_cmd: " << shared->compCmd;
|
if (QFileInfo::exists(vidPath))
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QProcess::execute("ffmpeg", snapArgsA);
|
|
||||||
QProcess::execute("ffmpeg", snapArgsB);
|
|
||||||
|
|
||||||
if (QFile::exists(imgAPath) && QFile::exists(imgBPath))
|
|
||||||
{
|
{
|
||||||
QProcess extComp;
|
found = true; break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dTime = dTime.addSecs(1);
|
||||||
|
|
||||||
extComp.start(compArgs[0], compArgs.mid(1));
|
vidPath = shared->buffPath + "/live/" + dTime.toString(DATETIME_FMT) + shared->streamExt;
|
||||||
extComp.waitForFinished();
|
|
||||||
|
|
||||||
float score = 0;
|
|
||||||
|
|
||||||
if (shared->outputType == "stdout")
|
|
||||||
{
|
|
||||||
score = getFloatFromExe(extComp.readAllStandardOutput());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
score = getFloatFromExe(extComp.readAllStandardError());
|
|
||||||
}
|
|
||||||
|
|
||||||
qInfo() << compArgs.join(" ") << " --result: " << QString::number(score);
|
|
||||||
|
|
||||||
if (eventQue.inQue)
|
|
||||||
{
|
|
||||||
eventQue.queAge += 4;
|
|
||||||
|
|
||||||
if (eventQue.score < score)
|
|
||||||
{
|
|
||||||
eventQue.score = score;
|
|
||||||
eventQue.imgPath = imgBPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
eventQue.vidList.append(vidAPath);
|
|
||||||
eventQue.vidList.append(vidBPath);
|
|
||||||
|
|
||||||
if (eventQue.queAge >= shared->evMaxSecs)
|
|
||||||
{
|
|
||||||
eventQue.inQue = false;
|
|
||||||
|
|
||||||
shared->recList.append(eventQue);
|
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (score >= shared->imgThresh)
|
|
||||||
{
|
|
||||||
qInfo() << "--threshold_meet: " << QString::number(shared->imgThresh);
|
|
||||||
|
|
||||||
eventQue.score = score;
|
|
||||||
eventQue.imgPath = imgBPath;
|
|
||||||
eventQue.inQue = true;
|
|
||||||
eventQue.queAge = 0;
|
|
||||||
eventQue.timeStamp = QDateTime::currentDateTime().toString(DATETIME_FMT);
|
|
||||||
|
|
||||||
eventQue.vidList.append(vidAPath);
|
|
||||||
eventQue.vidList.append(vidBPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vidAPath.clear();
|
if (found)
|
||||||
vidBPath.clear();
|
{
|
||||||
|
auto imgPath = shared->buffPath + "/img/" + QFileInfo(vidPath).baseName() + "-%03d" + ".bmp";
|
||||||
|
|
||||||
|
QProcess ffmpeg;
|
||||||
|
QStringList args;
|
||||||
|
QString imgA;
|
||||||
|
QString imgB;
|
||||||
|
|
||||||
|
args.append("ffmpeg");
|
||||||
|
args.append("-hide_banner");
|
||||||
|
//args.append("-loglevel");
|
||||||
|
//args.append("panic");
|
||||||
|
args.append("-y");
|
||||||
|
args.append("-i");
|
||||||
|
args.append(vidPath);
|
||||||
|
args.append("-vf");
|
||||||
|
args.append("fps=1/1");
|
||||||
|
args.append(imgPath);
|
||||||
|
|
||||||
|
ffmpeg.start(args[0], args.mid(1));
|
||||||
|
ffmpeg.waitForFinished();
|
||||||
|
|
||||||
|
for (auto i = 1; i <= SEG_SIZE; ++i)
|
||||||
|
{
|
||||||
|
auto imgNum = QString::number(i).rightJustified(3, '0');
|
||||||
|
auto imgPath = shared->buffPath + "/img/" + QFileInfo(vidPath).baseName() + "-" + imgNum + ".bmp";
|
||||||
|
|
||||||
|
if (QFileInfo::exists(imgPath))
|
||||||
|
{
|
||||||
|
if (imgA.isEmpty()) imgA = imgPath;
|
||||||
|
else if (imgB.isEmpty()) imgB = imgPath;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eTimer.restart();
|
||||||
|
|
||||||
|
QProcess extComp;
|
||||||
|
|
||||||
|
auto compArgs = buildArgs(imgA, imgB);
|
||||||
|
|
||||||
|
extComp.start(compArgs[0], compArgs.mid(1));
|
||||||
|
extComp.waitForFinished();
|
||||||
|
|
||||||
|
float score = 0;
|
||||||
|
|
||||||
|
if (shared->outputType == "stdout")
|
||||||
|
{
|
||||||
|
score = getFloatFromExe(extComp.readAllStandardOutput());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
score = getFloatFromExe(extComp.readAllStandardError());
|
||||||
|
}
|
||||||
|
|
||||||
|
qInfo() << compArgs.join(" ") << " --result: " << QString::number(score);
|
||||||
|
|
||||||
|
if (score >= shared->imgThresh)
|
||||||
|
{
|
||||||
|
qInfo() << "--threshold_meet: " << QString::number(shared->imgThresh);
|
||||||
|
|
||||||
|
if (eventQue.score < score)
|
||||||
|
{
|
||||||
|
eventQue.imgPath = imgB;
|
||||||
|
eventQue.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventQue.inQue = true;
|
||||||
|
eventQue.queAge = 0;
|
||||||
|
eventQue.timeStamp = QDateTime::currentDateTimeUtc().toString(DATETIME_FMT);
|
||||||
|
|
||||||
|
if (!eventQue.vidList.contains(vidPath))
|
||||||
|
{
|
||||||
|
eventQue.vidList.append(vidPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imgA.clear();
|
||||||
|
imgB.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit loop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QTimer::singleShot(SEG_SIZE + 4, this, &DetectLoop::exec);
|
||||||
|
|
||||||
|
dTime = QDateTime::currentDateTimeUtc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
class DetectLoop : public QFileSystemWatcher
|
class DetectLoop : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -27,31 +27,33 @@ private:
|
||||||
QString vidBName;
|
QString vidBName;
|
||||||
QStringList prevClips;
|
QStringList prevClips;
|
||||||
QTimer *pcTimer;
|
QTimer *pcTimer;
|
||||||
|
QTimer *evTimer;
|
||||||
|
QDateTime dTime;
|
||||||
QElapsedTimer eTimer;
|
QElapsedTimer eTimer;
|
||||||
evt_t eventQue;
|
evt_t eventQue;
|
||||||
shared_t *shared;
|
shared_t *shared;
|
||||||
|
|
||||||
float getFloatFromExe(const QByteArray &line);
|
float getFloatFromExe(const QByteArray &line);
|
||||||
QStringList buildArgs(const QString &prev, const QString &next);
|
QStringList buildArgs(const QString &prev, const QString &next);
|
||||||
QStringList buildSnapArgs(const QString &vidSrc, const QString &imgPath);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void reset();
|
void reset();
|
||||||
void pcBreak();
|
void pcBreak();
|
||||||
void updated(const QString &path);
|
void evBreak();
|
||||||
|
void exec();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit DetectLoop(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
explicit DetectLoop(shared_t *shared, QThread *thr, QObject *parent = nullptr);
|
||||||
|
|
||||||
void exec();
|
|
||||||
QString statusLine();
|
QString statusLine();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void starving();
|
void starving();
|
||||||
|
void loop();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DETECT_LOOP_H
|
#endif // DETECT_LOOP_H
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
RecordLoop::RecordLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : QProcess(parent)
|
RecordLoop::RecordLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : QProcess(parent)
|
||||||
{
|
{
|
||||||
checkTimer = 0;
|
checkTimer = 0;
|
||||||
|
status = 0;
|
||||||
shared = sharedRes;
|
shared = sharedRes;
|
||||||
|
|
||||||
connect(thr, &QThread::started, this, &RecordLoop::init);
|
connect(thr, &QThread::started, this, &RecordLoop::init);
|
||||||
|
@ -23,6 +24,7 @@ RecordLoop::RecordLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : QPr
|
||||||
connect(this, &RecordLoop::readyReadStandardOutput, this, &RecordLoop::resetTime);
|
connect(this, &RecordLoop::readyReadStandardOutput, this, &RecordLoop::resetTime);
|
||||||
connect(this, &RecordLoop::readyReadStandardError, this, &RecordLoop::resetTime);
|
connect(this, &RecordLoop::readyReadStandardError, this, &RecordLoop::resetTime);
|
||||||
connect(this, &RecordLoop::started, this, &RecordLoop::resetTime);
|
connect(this, &RecordLoop::started, this, &RecordLoop::resetTime);
|
||||||
|
connect(this, &RecordLoop::finished, this, &RecordLoop::segFinished);
|
||||||
|
|
||||||
moveToThread(thr);
|
moveToThread(thr);
|
||||||
}
|
}
|
||||||
|
@ -46,31 +48,56 @@ void RecordLoop::init()
|
||||||
restart();
|
restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RecordLoop::camCmdFromConf()
|
void RecordLoop::segFinished(int retCode)
|
||||||
{
|
{
|
||||||
auto ret = "ffmpeg -hide_banner -y -i '" + shared->recordUri + "' -strftime 1 -strftime_mkdir 1 ";
|
status = retCode;
|
||||||
|
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList RecordLoop::camCmdFromConf()
|
||||||
|
{
|
||||||
|
auto tobj = QDateTime::currentDateTimeUtc();
|
||||||
|
auto ret = QStringList();
|
||||||
|
|
||||||
|
ret.append("ffmpeg");
|
||||||
|
ret.append("-hide_banner");
|
||||||
|
ret.append("-y");
|
||||||
|
ret.append("-i");
|
||||||
|
ret.append(shared->recordUri);
|
||||||
|
|
||||||
if (shared->recordUri.contains("rtsp"))
|
if (shared->recordUri.contains("rtsp"))
|
||||||
{
|
{
|
||||||
ret += "-rtsp_transport udp ";
|
ret.append("-rtsp_transport");
|
||||||
|
ret.append("udp");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shared->vidCodec != "copy")
|
if (shared->vidCodec != "copy")
|
||||||
{
|
{
|
||||||
ret += "-vf fps=" + QString::number(shared->recFps) + ",scale=" + shared->recScale + " ";
|
ret.append("-vf");
|
||||||
|
ret.append("fps=" + QString::number(shared->recFps) + ",scale=" + shared->recScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret += "-vcodec " + shared->vidCodec + " ";
|
ret.append("-vcodec"); ret.append(shared->vidCodec);
|
||||||
ret += "-acodec " + shared->audCodec + " ";
|
ret.append("-acodec"); ret.append(shared->audCodec);
|
||||||
ret += "-reset_timestamps 1 -sc_threshold 0 -g 2 -force_key_frames 'expr:gte(t, n_forced * 2)' -segment_time 2 -f segment ";
|
ret.append("-reset_timestamps");
|
||||||
ret += shared->buffPath + "/live/" + QString(STRFTIME_FMT) + shared->streamExt;
|
ret.append("1");
|
||||||
|
ret.append("-sc_threshold");
|
||||||
|
ret.append("0");
|
||||||
|
ret.append("-g");
|
||||||
|
ret.append("2");
|
||||||
|
ret.append("-force_key_frames");
|
||||||
|
ret.append("expr:gte(t, n_forced * 2)");
|
||||||
|
ret.append("-t");
|
||||||
|
ret.append(QString::number(SEG_SIZE));
|
||||||
|
ret.append(shared->buffPath + "/live/" + tobj.toString(DATETIME_FMT) + shared->streamExt);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RecordLoop::statusLine()
|
QString RecordLoop::statusLine()
|
||||||
{
|
{
|
||||||
if (state() == QProcess::Running)
|
if ((status == 0) || (status == 255))
|
||||||
{
|
{
|
||||||
return "OK ";
|
return "OK ";
|
||||||
}
|
}
|
||||||
|
@ -90,20 +117,13 @@ void RecordLoop::restart()
|
||||||
if (state() == QProcess::Running)
|
if (state() == QProcess::Running)
|
||||||
{
|
{
|
||||||
terminate();
|
terminate();
|
||||||
waitForFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cmdLine = camCmdFromConf();
|
|
||||||
auto args = parseArgs(cmdLine.toUtf8(), -1);
|
|
||||||
|
|
||||||
qInfo() << "start recording command: " << cmdLine;
|
|
||||||
|
|
||||||
if (args.isEmpty())
|
|
||||||
{
|
|
||||||
qCritical() << "err: couldn't parse a program name";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
resetTime();
|
||||||
|
|
||||||
|
auto args = camCmdFromConf();
|
||||||
|
|
||||||
setProgram(args[0]);
|
setProgram(args[0]);
|
||||||
setArguments(args.mid(1));
|
setArguments(args.mid(1));
|
||||||
|
|
||||||
|
|
|
@ -28,12 +28,14 @@ private:
|
||||||
|
|
||||||
shared_t *shared;
|
shared_t *shared;
|
||||||
QTimer *checkTimer;
|
QTimer *checkTimer;
|
||||||
|
int status;
|
||||||
|
|
||||||
QString camCmdFromConf();
|
QStringList camCmdFromConf();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void restart();
|
void restart();
|
||||||
|
void segFinished(int retCode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user