I'm going to test a move away from opencv's videoio module.
Videoio simply refuses to open any video file even with
FFMPEG builtin. I tested old v2.2 code and even that failed
on a fresh install of ubuntu sever so this tells me an
update on opencv's side broke something.

This issue is not new and frankly I'm tired of chasing it.
I'm giving QT's QMediaPlayer a try to see how it works out.
Will still need opencv for the absdiff and threshold
functions, otherwise I would have dropped the API
altogeather.

Now that the app has QT::Multimedia, QT6 is now the minimum
version it will support. CMakeList.txt and the setup script
updated accordingly.
This commit is contained in:
Maurice ONeal 2023-05-20 19:18:55 -04:00
parent 40ef014e0f
commit 496bac7d7e
7 changed files with 138 additions and 119 deletions

View File

@ -13,8 +13,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(${OpenCV_INCLUDE_DIRS})
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)
find_package(QT NAMES Qt6 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Multimedia REQUIRED)
find_package(OpenCV REQUIRED)
add_executable(mow
@ -31,4 +31,4 @@ add_executable(mow
src/camera.cpp
)
target_link_libraries(mow Qt${QT_VERSION_MAJOR}::Core ${OpenCV_LIBS})
target_link_libraries(mow Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Multimedia ${OpenCV_LIBS})

View File

@ -1,24 +1,4 @@
#!/bin/sh
apt update -y
apt install -y pkg-config
apt install -y cmake
apt install -y make
apt install -y g++
apt install -y wget
apt install -y unzip
apt install -y git
apt install -y ffmpeg
apt install -y libavcodec-dev
apt install -y libavformat-dev
apt install -y libavutil-dev
apt install -y libswscale-dev
apt install -y libgstreamer1.0-dev
apt install -y x264
apt install -y libx264-dev
apt install -y libilmbase-dev
apt install -y libopencv-dev
apt install -y qtbase5-dev
apt install -y qtchooser
apt install -y qt5-qmake
apt install -y qtbase5-dev-tools
apt install -y apache2
apt install -y pkg-config cmake make g++ wget unzip git
apt install -y ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libgstreamer1.0-dev x264 libx264-dev libilmbase-dev libopencv-dev qt6-base-dev qtchooser qmake6 qt6-base-dev-tools qt6-multimedia-dev apache2

View File

@ -19,6 +19,7 @@ Camera::Camera(QObject *parent) : QObject(parent)
shared.camName.clear();
shared.retCode = 0;
shared.maxScore = 0;
shared.pixThresh = 50;
shared.imgThresh = 800;
shared.maxEvents = 40;
@ -240,7 +241,8 @@ bool EventLoop::exec()
if (wrOutVod(event))
{
genHTMLvod(event.evName);
imwrite(QString("events/" + event.evName + ".jpg").toUtf8().data(), event.thumbnail);
event.thumbnail.save(QString("events/" + event.evName + ".jpg"));
}
shared->recList.removeFirst();
@ -314,16 +316,22 @@ bool EventLoop::wrOutVod(const evt_t &event)
DetectLoop::DetectLoop(shared_t *sharedRes, QThread *thr, QObject *parent) : Loop(sharedRes, thr, parent)
{
heartBeat = 0;
evId = 0;
pcId = 0;
heartBeat = 0;
evId = 0;
pcId = 0;
player = new QMediaPlayer(this);
frameAnalyzer = new MoDetect(shared, this);
player->setVideoSink(frameAnalyzer);
connect(player, &QMediaPlayer::errorOccurred, this, &DetectLoop::playError);
}
void DetectLoop::init()
{
thread()->sleep(1);
resetTimers(); Loop::init();
resetTimers();
}
void DetectLoop::resetTimers()
@ -357,7 +365,8 @@ void DetectLoop::timerEvent(QTimerEvent *event)
shared->curEvent.srcPaths.clear();
shared->curEvent.evName.clear();
shared->curEvent.thumbnail.release();
shared->curEvent.thumbnail = QImage();
shared->maxScore = 0;
}
@ -380,6 +389,31 @@ void DetectLoop::timerEvent(QTimerEvent *event)
}
}
void DetectLoop::resetDetect()
{
if (player->playbackState() != QMediaPlayer::PlayingState)
{
frameAnalyzer->stop();
exec();
}
}
void DetectLoop::playError(QMediaPlayer::Error error, const QString &errorString)
{
Q_UNUSED(error)
detLog("err: media player error - " + errorString, shared);
resetDetect();
}
void DetectLoop::playStateChanged(QMediaPlayer::PlaybackState newState)
{
Q_UNUSED(newState)
resetDetect();
}
bool DetectLoop::exec()
{
QFile fileIn("stream.m3u8");
@ -429,12 +463,9 @@ bool DetectLoop::exec()
{
prevTs = tsPath;
if (moDetect(tsPath, thread(), shared))
{
shared->curEvent.srcPaths.append(tsPath);
shared->skipCmd = true;
}
player->setSource(QUrl::fromLocalFile(tsPath));
frameAnalyzer->play(tsPath);
player->play();
}
return Loop::exec();

View File

@ -114,16 +114,21 @@ class DetectLoop : public Loop
private:
int pcId;
int evId;
QString prevTs;
int pcId;
int evId;
QString prevTs;
QMediaPlayer *player;
MoDetect *frameAnalyzer;
void resetTimers();
void resetDetect();
void timerEvent(QTimerEvent *event);
private slots:
void init();
void playError(QMediaPlayer::Error error, const QString &errorString);
void playStateChanged(QMediaPlayer::PlaybackState newState);
public:

View File

@ -23,6 +23,10 @@
#include <QFile>
#include <QDateTime>
#include <QThread>
#include <QMediaPlayer>
#include <QVideoSink>
#include <QVideoFrame>
#include <QImage>
#include <opencv4/opencv2/opencv.hpp>
#include <opencv4/opencv2/videoio.hpp>
@ -31,7 +35,7 @@
using namespace cv;
using namespace std;
#define APP_VER "3.0.t3"
#define APP_VER "3.0.t4"
#define APP_NAME "Motion Watch"
#define APP_BIN "mow"
#define REC_LOG_NAME "rec_log_lines.html"
@ -42,7 +46,7 @@ struct evt_t
{
QString evName;
QStringList srcPaths;
Mat thumbnail;
QImage thumbnail;
};
struct shared_t

View File

@ -12,93 +12,70 @@
#include "mo_detect.h"
bool imgDiff(const Mat &prev, const Mat &next, int &score, shared_t *share)
MoDetect::MoDetect(shared_t *share, QObject *parent) : QVideoSink(parent)
{
Mat prevGray;
Mat nextGray;
shared = share;
cvtColor(prev, prevGray, COLOR_BGR2GRAY);
cvtColor(next, nextGray, COLOR_BGR2GRAY);
Mat diff;
absdiff(prevGray, nextGray, diff);
threshold(diff, diff, share->pixThresh, 255, THRESH_BINARY);
score = countNonZero(diff);
detLog("diff_score: " + QString::number(score) + " thresh: " + QString::number(share->imgThresh), share);
return score >= share->imgThresh;
connect(this, &MoDetect::videoFrameChanged, this, &MoDetect::newFrame);
}
bool moDetect(const QString &buffFile, QThread *thr, shared_t *share)
void MoDetect::stop()
{
auto score = 0;
auto mod = false;
baseImg = QImage(); gap = 0; shared->maxScore = 0;
}
detLog("stream_clip: " + buffFile, share);
void MoDetect::play(const QString &path)
{
filePath = path;
}
VideoCapture capture;
if (!capture.open(buffFile.toUtf8().data(), CAP_FFMPEG))
void MoDetect::newFrame()
{
if (!baseImg.isNull())
{
thr->usleep(500);
capture.open(buffFile.toUtf8().data(), CAP_FFMPEG);
baseImg = videoFrame().toImage().convertToFormat(QImage::Format_Grayscale8);
}
if (capture.isOpened())
else if (shared->frameGap > gap)
{
Mat prev;
Mat next;
int fps = capture.get(cv::CAP_PROP_FPS);
for (auto gap = 0, frm = fps; capture.grab(); ++gap, ++frm)
{
if (frm == fps) thr->sleep(1); frm = 1;
if (prev.empty())
{
capture.retrieve(prev);
}
else if (gap == (share->frameGap - 1))
{
capture.retrieve(next);
if (!next.empty())
{
if (imgDiff(prev, next, score, share))
{
mod = true;
if (share->maxScore <= score)
{
share->maxScore = score;
resize(next, share->curEvent.thumbnail, Size(720, 480), INTER_LINEAR);
}
}
}
prev = next.clone();
gap = 0;
next.release();
}
else
{
capture.grab();
}
}
gap++;
}
else
{
detLog("err: failed to open: " + buffFile + " after 500 msecs. giving up.", share);
auto nextImg = videoFrame().toImage();
auto nextImgGray = nextImg.convertToFormat(QImage::Format_Grayscale8);
auto score = 0;
if (diff(baseImg, nextImgGray, &score))
{
shared->skipCmd = true;
if (!shared->curEvent.srcPaths.contains(filePath))
{
shared->curEvent.srcPaths.append(filePath);
if (shared->maxScore <= score)
{
shared->maxScore = score;
shared->curEvent.thumbnail = nextImg;
}
}
}
}
capture.release();
return mod;
}
bool MoDetect::diff(QImage &base, QImage &next, int *score)
{
Mat baseMat = Mat(base.height(), base.width(), CV_8U, base.bits(), base.bytesPerLine());
Mat nextMat = Mat(next.height(), next.width(), CV_8U, next.bits(), next.bytesPerLine());
Mat diffMat;
absdiff(baseMat, nextMat, diffMat);
threshold(diffMat, diffMat, shared->pixThresh, 255, THRESH_BINARY);
*score = countNonZero(diffMat);
detLog("diff_score: " + QString::number(*score) + " thresh: " + QString::number(shared->imgThresh), shared);
return *score >= shared->imgThresh;
}

View File

@ -16,7 +16,29 @@
#include "common.h"
#include "logger.h"
bool imgDiff(const Mat &prev, const Mat &next, int &score, shared_t *share);
bool moDetect(const QString &buffFile, QThread *thr, shared_t *share);
class MoDetect : public QVideoSink
{
Q_OBJECT
private:
QImage baseImg;
QString filePath;
shared_t *shared;
int gap;
bool diff(QImage &base, QImage &next, int *score);
private slots:
void newFrame();
public:
void play(const QString &path);
void stop();
explicit MoDetect(shared_t *share, QObject *parent = nullptr);
};
#endif // MO_DETECT_H