-added 'null' key word to img_comp_cmd parameter so motion
 detection can be turned off if desired
-fixed footage directory max_events_bytes by having it loop
 through the directory at least 100 times
This commit is contained in:
zii 2025-07-22 21:06:44 -04:00
parent 7c72d26e46
commit c0f167e5b1
4 changed files with 48 additions and 24 deletions

View File

@ -2,7 +2,7 @@
JustMotion is a simple, lightweight video surveillance application utilizing JustMotion is a simple, lightweight video surveillance application utilizing
the server-client model that doesn't try to re-invent the wheel. The source the server-client model that doesn't try to re-invent the wheel. The source
code for both server and client are available this repository and can be code for both server and client are available in this repository and can be
compliled and/or installed separately. compliled and/or installed separately.
# JustMotion-Server # # JustMotion-Server #
@ -13,10 +13,10 @@ motion to permanent storage. The main advantage of this is reduced storage
requirements as opposed to continuous recording because only video footage requirements as opposed to continuous recording because only video footage
of interest is kept in storage. of interest is kept in storage.
The server implements the principle of doing the least as needed, as a result The server implements the principle of doing the least as needed. As a result
it extremely lightweight with the fact it doesn't attempt to re-implement much it is extremely lightweight with the fact it doesn't attempt to re-implement
of it's functions internally but will instead rely on external applications much of it's functions internally but will instead rely on external
that already implement the functions very well. applications that already implement the functions very well.
It doesn't have a builtin user interface so instead external applications are It doesn't have a builtin user interface so instead external applications are
more than welcome to interface with the buffer/footage directories to more than welcome to interface with the buffer/footage directories to
@ -26,14 +26,14 @@ implement a user interface of any flavor.
JustMotion-Client is the client portion of this application that actually JustMotion-Client is the client portion of this application that actually
implement a user interface. Utilizing the same principle of doing the least as implement a user interface. Utilizing the same principle of doing the least as
needed, it uses an external video player to play m3u8 playlist files mounted needed, it uses an external video player to play m3u8 playlist files located
as an ssh filesystem to play live or recorded footage from the server. at the server's buffer/footage directories. It mounts the server as an ssh
filesystem to access such directories so no need to open any addtional ports
if your server already has working ssh access.
### Usage (server) ### ### Usage (server) ###
``` ```
JustMotion 1.0
Usage: jmotion <argument> Usage: jmotion <argument>
-h : display usage information about this application. -h : display usage information about this application.
@ -53,9 +53,6 @@ Usage: jmotion <argument>
The config file is a simple text file that contain parameters that dictate the The config file is a simple text file that contain parameters that dictate the
behavior of the server for each camera located in the /etc/jmotion directory. behavior of the server for each camera located in the /etc/jmotion directory.
The config for each camera can have any unique name within that directory.
Below is an example of a config file with all parameters supported and
descriptions.
``` ```
# Motion Watch config file # Motion Watch config file
# #
@ -106,9 +103,8 @@ img_comp_cmd = compare -metric FUZZ &prev& &next& /dev/null
# formatted so the app will be required to support this format. also avoid # formatted so the app will be required to support this format. also avoid
# outputting any special chars, only numeric chars with a single '.' if # outputting any special chars, only numeric chars with a single '.' if
# outputting a decimal value. magick is the default if not defined in the # outputting a decimal value. magick is the default if not defined in the
# config file. the special string &prev& will be substituted with the path # config file. this parameter can also be set to 'null' as a means to turn
# to the "previous" bitmap image, behind in time stamp to the image path # off motion detection.
# subtituted in &next&.
# #
img_comp_out = stderr img_comp_out = stderr
# this is the standard output stream the app defined in img_comp_cmd will # this is the standard output stream the app defined in img_comp_cmd will

View File

@ -32,7 +32,7 @@
using namespace std; using namespace std;
#define APP_VERSION "1.0" #define APP_VERSION "1.1"
#define APP_NAME "JustMotion" #define APP_NAME "JustMotion"
#define APP_TARGET "jmotion" #define APP_TARGET "jmotion"
#define DATETIME_FMT "yyyyMMddhhmmss" #define DATETIME_FMT "yyyyMMddhhmmss"

View File

@ -29,21 +29,36 @@ void DetectLoop::init()
pcTimer = new QTimer(this); pcTimer = new QTimer(this);
evtTimer = new QTimer(this); evtTimer = new QTimer(this);
connect(pcTimer, &QTimer::timeout, this, &DetectLoop::pcBreak); setupBuffDir(shared->buffPath);
connect(evtTimer, &QTimer::timeout, this, &DetectLoop::reset);
connect(pcTimer, &QTimer::timeout, this, &DetectLoop::pcBreak);
connect(this, &QFileSystemWatcher::directoryChanged, this, &DetectLoop::updated); connect(this, &QFileSystemWatcher::directoryChanged, this, &DetectLoop::updated);
pcTimer->start(shared->postSecs * 1000); pcTimer->start(shared->postSecs * 1000);
evtTimer->setSingleShot(true);
setupBuffDir(shared->buffPath); if (shared->compCmd.toLower() != "null")
{
connect(evtTimer, &QTimer::timeout, this, &DetectLoop::reset);
evtTimer->setSingleShot(true);
eTimer.start();
}
else
{
eTimer.invalidate();
}
addPath(shared->buffPath + "/vid"); addPath(shared->buffPath + "/vid");
} }
void DetectLoop::updated(const QString &path) void DetectLoop::updated(const QString &path)
{ {
eTimer.start(); if (shared->compCmd.toLower() != "null")
{
eTimer.start();
}
auto clips = lsFilesInDir(path, shared->streamExt); auto clips = lsFilesInDir(path, shared->streamExt);
auto index = clips.indexOf(vidBName); auto index = clips.indexOf(vidBName);
@ -153,7 +168,11 @@ QStringList DetectLoop::buildSnapArgs(const QString &vidSrc, const QString &imgP
QString DetectLoop::statusLine() QString DetectLoop::statusLine()
{ {
if (eTimer.elapsed() >= 5000) if (!eTimer.isValid())
{
return "OFF ";
}
else if (eTimer.elapsed() >= 5000)
{ {
emit starving(); emit starving();
@ -187,7 +206,7 @@ void DetectLoop::exec()
QProcess::execute("ffmpeg", snapArgsA); QProcess::execute("ffmpeg", snapArgsA);
QProcess::execute("ffmpeg", snapArgsB); QProcess::execute("ffmpeg", snapArgsB);
if (QFile::exists(imgAPath) && QFile::exists(imgBPath)) if (QFile::exists(imgAPath) && QFile::exists(imgBPath) && (shared->compCmd.toLower() != "null"))
{ {
QProcess extComp; QProcess extComp;

View File

@ -150,7 +150,7 @@ void EventLoop::exec()
auto names = lsFilesInDir(shared->recPath + "/vid", shared->recExt); auto names = lsFilesInDir(shared->recPath + "/vid", shared->recExt);
if (byteSize(shared->recPath) > shared->evtMaxBytes) for (auto i = 0; (byteSize(shared->recPath) >= shared->evtMaxBytes); ++i)
{ {
auto nameOnly = QFileInfo(shared->recPath + "/vid/" + names[0]).baseName(); auto nameOnly = QFileInfo(shared->recPath + "/vid/" + names[0]).baseName();
@ -163,6 +163,15 @@ void EventLoop::exec()
names.removeFirst(); names.removeFirst();
dirUpdated = true; dirUpdated = true;
if (i > 100)
{
// loop through 100 times before breaking the for loop, prevents infinte looping
// if bytes size of the dir is not being read correctly or there is a lot to
// delete (don't want to keep EventLoop busy doing this for too long).
break;
}
} }
if (dirUpdated) if (dirUpdated)