mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
cleanup, split
This commit is contained in:
parent
c5f5e4ffa9
commit
de1445cdd8
205
cameraworker.cpp
Normal file
205
cameraworker.cpp
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
This program is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "cameraworker.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
|
||||
CameraWorker::CameraWorker(int index)
|
||||
: clock(nullptr)
|
||||
, camIndex(index)
|
||||
, refCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CameraWorker::onStart()
|
||||
{
|
||||
clock = new QTimer(this);
|
||||
clock->setSingleShot(false);
|
||||
clock->setInterval(5);
|
||||
|
||||
connect(clock, &QTimer::timeout, this, &CameraWorker::doWork);
|
||||
|
||||
emit started();
|
||||
}
|
||||
|
||||
void CameraWorker::_suspend()
|
||||
{
|
||||
qDebug() << "Suspend";
|
||||
clock->stop();
|
||||
unsubscribe();
|
||||
}
|
||||
|
||||
void CameraWorker::_resume()
|
||||
{
|
||||
qDebug() << "Resume";
|
||||
subscribe();
|
||||
clock->start();
|
||||
}
|
||||
|
||||
void CameraWorker::_setProp(int prop, double val)
|
||||
{
|
||||
props[prop] = val;
|
||||
|
||||
if (cam.isOpened())
|
||||
cam.set(prop, val);
|
||||
}
|
||||
|
||||
double CameraWorker::_getProp(int prop)
|
||||
{
|
||||
if (!props.contains(prop))
|
||||
{
|
||||
subscribe();
|
||||
props[prop] = cam.get(prop);
|
||||
unsubscribe();
|
||||
qDebug() << "ASKED " << prop << " VAL " << props[prop];
|
||||
}
|
||||
|
||||
return props.value(prop);
|
||||
}
|
||||
|
||||
void CameraWorker::probeResolutions()
|
||||
{
|
||||
if (resolutions.isEmpty())
|
||||
{
|
||||
subscribe();
|
||||
|
||||
// probe resolutions (TODO: add more)
|
||||
QList<QSize> propbeRes = {
|
||||
QSize( 160, 120), // QQVGA
|
||||
QSize( 320, 240), // HVGA
|
||||
QSize(1024, 768), // XGA
|
||||
QSize( 432, 240), // WQVGA
|
||||
QSize( 640, 360), // nHD
|
||||
};
|
||||
|
||||
for (QSize res : propbeRes)
|
||||
{
|
||||
cam.set(CV_CAP_PROP_FRAME_WIDTH, res.width());
|
||||
cam.set(CV_CAP_PROP_FRAME_HEIGHT, res.height());
|
||||
|
||||
double w = cam.get(CV_CAP_PROP_FRAME_WIDTH);
|
||||
double h = cam.get(CV_CAP_PROP_FRAME_HEIGHT);
|
||||
|
||||
//qDebug() << "PROBING:" << res << " got " << w << h;
|
||||
|
||||
if (!resolutions.contains(QSize(w,h)))
|
||||
resolutions.append(QSize(w,h));
|
||||
}
|
||||
|
||||
unsubscribe();
|
||||
}
|
||||
|
||||
qDebug() << resolutions;
|
||||
|
||||
emit resProbingFinished(resolutions);
|
||||
}
|
||||
|
||||
void CameraWorker::applyProps()
|
||||
{
|
||||
if (!cam.isOpened())
|
||||
return;
|
||||
|
||||
for(int prop : props.keys())
|
||||
cam.set(prop, props.value(prop));
|
||||
}
|
||||
|
||||
void CameraWorker::subscribe()
|
||||
{
|
||||
if (refCount == 0)
|
||||
{
|
||||
if (!cam.isOpened())
|
||||
{
|
||||
cam.open(camIndex);
|
||||
applyProps(); // restore props
|
||||
}
|
||||
}
|
||||
|
||||
refCount++;
|
||||
}
|
||||
|
||||
void CameraWorker::unsubscribe()
|
||||
{
|
||||
refCount--;
|
||||
|
||||
if(refCount <= 0)
|
||||
{
|
||||
cam.release();
|
||||
}
|
||||
}
|
||||
|
||||
void CameraWorker::doWork()
|
||||
{
|
||||
if (!cam.isOpened())
|
||||
return;
|
||||
|
||||
if (queue.size() > 3)
|
||||
{
|
||||
queue.dequeue();
|
||||
return;
|
||||
}
|
||||
|
||||
cam >> frame;
|
||||
//qDebug() << "Decoding frame";
|
||||
mutex.lock();
|
||||
|
||||
queue.enqueue(frame);
|
||||
mutex.unlock();
|
||||
|
||||
emit newFrameAvailable();
|
||||
}
|
||||
|
||||
bool CameraWorker::hasFrame()
|
||||
{
|
||||
mutex.lock();
|
||||
bool b = !queue.empty();
|
||||
mutex.unlock();
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
cv::Mat3b CameraWorker::dequeueFrame()
|
||||
{
|
||||
mutex.lock();
|
||||
cv::Mat3b f = queue.dequeue();
|
||||
mutex.unlock();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void CameraWorker::suspend()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "_suspend");
|
||||
}
|
||||
|
||||
void CameraWorker::resume()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "_resume");
|
||||
}
|
||||
|
||||
void CameraWorker::setProp(int prop, double val)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "_setProp", Q_ARG(int, prop), Q_ARG(double, val));
|
||||
}
|
||||
|
||||
double CameraWorker::getProp(int prop)
|
||||
{
|
||||
double ret = 0.0;
|
||||
QMetaObject::invokeMethod(this, "_getProp", Qt::BlockingQueuedConnection, Q_RETURN_ARG(double, ret), Q_ARG(int, prop));
|
||||
|
||||
return ret;
|
||||
}
|
77
cameraworker.h
Normal file
77
cameraworker.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
This program is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef CAMERAWORKER_H
|
||||
#define CAMERAWORKER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QQueue>
|
||||
#include <QSize>
|
||||
|
||||
#include "opencv2/opencv.hpp"
|
||||
|
||||
class QTimer;
|
||||
|
||||
class CameraWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CameraWorker(int index);
|
||||
void doWork();
|
||||
bool hasFrame();
|
||||
cv::Mat3b dequeueFrame();
|
||||
|
||||
void suspend();
|
||||
void resume();
|
||||
void setProp(int prop, double val);
|
||||
double getProp(int prop); // blocking call!
|
||||
void probeResolutions();
|
||||
|
||||
public slots:
|
||||
void onStart();
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void newFrameAvailable();
|
||||
void resProbingFinished(QList<QSize> res);
|
||||
|
||||
private slots:
|
||||
void _suspend();
|
||||
void _resume();
|
||||
void _setProp(int prop, double val);
|
||||
double _getProp(int prop);
|
||||
|
||||
private:
|
||||
void applyProps();
|
||||
void subscribe();
|
||||
void unsubscribe();
|
||||
|
||||
private:
|
||||
QMutex mutex;
|
||||
QQueue<cv::Mat3b> queue;
|
||||
QTimer* clock;
|
||||
cv::VideoCapture cam;
|
||||
cv::Mat3b frame;
|
||||
int camIndex;
|
||||
QMap<int, double> props;
|
||||
QList<QSize> resolutions;
|
||||
int refCount;
|
||||
};
|
||||
|
||||
#endif // CAMERAWORKER_H
|
6
qtox.pro
6
qtox.pro
|
@ -129,7 +129,8 @@ HEADERS += widget/form/addfriendform.h \
|
|||
widget/tool/chatactions/systemmessageaction.h \
|
||||
widget/tool/chatactions/actionaction.h \
|
||||
widget/maskablepixmapwidget.h \
|
||||
videosource.h
|
||||
videosource.h \
|
||||
cameraworker.h
|
||||
|
||||
SOURCES += \
|
||||
widget/form/addfriendform.cpp \
|
||||
|
@ -175,4 +176,5 @@ SOURCES += \
|
|||
widget/tool/chatactions/filetransferaction.cpp \
|
||||
widget/tool/chatactions/systemmessageaction.cpp \
|
||||
widget/tool/chatactions/actionaction.cpp \
|
||||
widget/maskablepixmapwidget.cpp
|
||||
widget/maskablepixmapwidget.cpp \
|
||||
cameraworker.cpp
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
|
||||
#include "camera.h"
|
||||
#include "widget.h"
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include "cameraworker.h"
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
Camera* Camera::instance = nullptr;
|
||||
|
||||
|
@ -28,18 +27,17 @@ Camera::Camera()
|
|||
, workerThread(nullptr)
|
||||
, worker(nullptr)
|
||||
{
|
||||
qDebug() << "New Worker";
|
||||
worker = new SelfCamWorker(0);
|
||||
worker = new CameraWorker(0);
|
||||
workerThread = new QThread();
|
||||
|
||||
worker->moveToThread(workerThread);
|
||||
|
||||
connect(workerThread, &QThread::started, worker, &SelfCamWorker::onStart);
|
||||
connect(workerThread, &QThread::finished, worker, &SelfCamWorker::deleteLater);
|
||||
connect(workerThread, &QThread::deleteLater, worker, &SelfCamWorker::deleteLater);
|
||||
connect(worker, &SelfCamWorker::started, this, &Camera::onWorkerStarted);
|
||||
connect(worker, &SelfCamWorker::newFrameAvailable, this, &Camera::onNewFrameAvailable);
|
||||
connect(worker, &SelfCamWorker::resProbingFinished, this, &Camera::onResProbingFinished);
|
||||
connect(workerThread, &QThread::started, worker, &CameraWorker::onStart);
|
||||
connect(workerThread, &QThread::finished, worker, &CameraWorker::deleteLater);
|
||||
connect(workerThread, &QThread::deleteLater, worker, &CameraWorker::deleteLater);
|
||||
connect(worker, &CameraWorker::started, this, &Camera::onWorkerStarted);
|
||||
connect(worker, &CameraWorker::newFrameAvailable, this, &Camera::onNewFrameAvailable);
|
||||
connect(worker, &CameraWorker::resProbingFinished, this, &Camera::onResProbingFinished);
|
||||
workerThread->start();
|
||||
}
|
||||
|
||||
|
@ -222,7 +220,7 @@ void Camera::lock()
|
|||
mutex.lock();
|
||||
|
||||
if (worker->hasFrame())
|
||||
currFrame = worker->deqeueFrame();
|
||||
currFrame = worker->dequeueFrame();
|
||||
}
|
||||
|
||||
void Camera::unlock()
|
||||
|
@ -242,192 +240,3 @@ Camera* Camera::getInstance()
|
|||
|
||||
return instance;
|
||||
}
|
||||
|
||||
// ====================
|
||||
// WORKER
|
||||
// ====================
|
||||
|
||||
SelfCamWorker::SelfCamWorker(int index)
|
||||
: clock(nullptr)
|
||||
, camIndex(index)
|
||||
, refCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void SelfCamWorker::onStart()
|
||||
{
|
||||
clock = new QTimer(this);
|
||||
clock->setSingleShot(false);
|
||||
clock->setInterval(5);
|
||||
|
||||
connect(clock, &QTimer::timeout, this, &SelfCamWorker::doWork);
|
||||
|
||||
emit started();
|
||||
}
|
||||
|
||||
void SelfCamWorker::_suspend()
|
||||
{
|
||||
qDebug() << "Suspend";
|
||||
clock->stop();
|
||||
unsubscribe();
|
||||
}
|
||||
|
||||
void SelfCamWorker::_resume()
|
||||
{
|
||||
qDebug() << "Resume";
|
||||
subscribe();
|
||||
clock->start();
|
||||
}
|
||||
|
||||
void SelfCamWorker::_setProp(int prop, double val)
|
||||
{
|
||||
props[prop] = val;
|
||||
|
||||
if (cam.isOpened())
|
||||
cam.set(prop, val);
|
||||
}
|
||||
|
||||
double SelfCamWorker::_getProp(int prop)
|
||||
{
|
||||
if (!props.contains(prop))
|
||||
{
|
||||
subscribe();
|
||||
props[prop] = cam.get(prop);
|
||||
unsubscribe();
|
||||
qDebug() << "ASKED " << prop << " VAL " << props[prop];
|
||||
}
|
||||
|
||||
return props.value(prop);
|
||||
}
|
||||
|
||||
void SelfCamWorker::probeResolutions()
|
||||
{
|
||||
if (resolutions.isEmpty())
|
||||
{
|
||||
subscribe();
|
||||
|
||||
// probe resolutions (TODO: add more)
|
||||
QList<QSize> propbeRes = {
|
||||
QSize( 160, 120), // QQVGA
|
||||
QSize( 320, 240), // HVGA
|
||||
QSize(1024, 768), // XGA
|
||||
QSize( 432, 240), // WQVGA
|
||||
QSize( 640, 360), // nHD
|
||||
};
|
||||
|
||||
for (QSize res : propbeRes)
|
||||
{
|
||||
cam.set(CV_CAP_PROP_FRAME_WIDTH, res.width());
|
||||
cam.set(CV_CAP_PROP_FRAME_HEIGHT, res.height());
|
||||
|
||||
double w = cam.get(CV_CAP_PROP_FRAME_WIDTH);
|
||||
double h = cam.get(CV_CAP_PROP_FRAME_HEIGHT);
|
||||
|
||||
//qDebug() << "PROBING:" << res << " got " << w << h;
|
||||
|
||||
if (!resolutions.contains(QSize(w,h)))
|
||||
resolutions.append(QSize(w,h));
|
||||
}
|
||||
|
||||
unsubscribe();
|
||||
}
|
||||
|
||||
qDebug() << resolutions;
|
||||
|
||||
emit resProbingFinished(resolutions);
|
||||
}
|
||||
|
||||
void SelfCamWorker::applyProps()
|
||||
{
|
||||
if (!cam.isOpened())
|
||||
return;
|
||||
|
||||
for(int prop : props.keys())
|
||||
cam.set(prop, props.value(prop));
|
||||
}
|
||||
|
||||
void SelfCamWorker::subscribe()
|
||||
{
|
||||
if (refCount == 0)
|
||||
{
|
||||
if (!cam.isOpened())
|
||||
{
|
||||
cam.open(camIndex);
|
||||
applyProps(); // restore props
|
||||
}
|
||||
}
|
||||
|
||||
refCount++;
|
||||
}
|
||||
|
||||
void SelfCamWorker::unsubscribe()
|
||||
{
|
||||
refCount--;
|
||||
|
||||
if(refCount <= 0)
|
||||
{
|
||||
cam.release();
|
||||
}
|
||||
}
|
||||
|
||||
void SelfCamWorker::doWork()
|
||||
{
|
||||
if (!cam.isOpened())
|
||||
return;
|
||||
|
||||
if (qeue.size() > 3)
|
||||
{
|
||||
qeue.dequeue();
|
||||
return;
|
||||
}
|
||||
|
||||
cam >> frame;
|
||||
//qDebug() << "Decoding frame";
|
||||
mutex.lock();
|
||||
|
||||
qeue.enqueue(frame);
|
||||
mutex.unlock();
|
||||
|
||||
emit newFrameAvailable();
|
||||
}
|
||||
|
||||
bool SelfCamWorker::hasFrame()
|
||||
{
|
||||
mutex.lock();
|
||||
bool b = !qeue.empty();
|
||||
mutex.unlock();
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
cv::Mat3b SelfCamWorker::deqeueFrame()
|
||||
{
|
||||
mutex.lock();
|
||||
cv::Mat3b f = qeue.dequeue();
|
||||
mutex.unlock();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void SelfCamWorker::suspend()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "_suspend");
|
||||
}
|
||||
|
||||
void SelfCamWorker::resume()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "_resume");
|
||||
}
|
||||
|
||||
void SelfCamWorker::setProp(int prop, double val)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "_setProp", Q_ARG(int, prop), Q_ARG(double, val));
|
||||
}
|
||||
|
||||
double SelfCamWorker::getProp(int prop)
|
||||
{
|
||||
double ret = 0.0;
|
||||
QMetaObject::invokeMethod(this, "_getProp", Qt::BlockingQueuedConnection, Q_RETURN_ARG(double, ret), Q_ARG(int, prop));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -26,58 +26,14 @@
|
|||
#include "opencv2/opencv.hpp"
|
||||
#include "videosource.h"
|
||||
|
||||
class CameraWorker;
|
||||
|
||||
/**
|
||||
* This class is a wrapper to share a camera's captured video frames
|
||||
* It allows objects to suscribe and unsuscribe to the stream, starting
|
||||
* the camera only when needed, and giving access to the last frames
|
||||
**/
|
||||
|
||||
class SelfCamWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SelfCamWorker(int index);
|
||||
void doWork();
|
||||
bool hasFrame();
|
||||
cv::Mat3b deqeueFrame();
|
||||
|
||||
void suspend();
|
||||
void resume();
|
||||
void setProp(int prop, double val);
|
||||
double getProp(int prop); // blocking call!
|
||||
void probeResolutions();
|
||||
|
||||
public slots:
|
||||
void onStart();
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void newFrameAvailable();
|
||||
void resProbingFinished(QList<QSize> res);
|
||||
|
||||
private slots:
|
||||
void _suspend();
|
||||
void _resume();
|
||||
void _setProp(int prop, double val);
|
||||
double _getProp(int prop);
|
||||
|
||||
private:
|
||||
void applyProps();
|
||||
void subscribe();
|
||||
void unsubscribe();
|
||||
|
||||
private:
|
||||
QMutex mutex;
|
||||
QQueue<cv::Mat3b> qeue;
|
||||
QTimer* clock;
|
||||
cv::VideoCapture cam;
|
||||
cv::Mat3b frame;
|
||||
int camIndex;
|
||||
QMap<int, double> props;
|
||||
QList<QSize> resolutions;
|
||||
int refCount;
|
||||
};
|
||||
|
||||
class Camera : public VideoSource
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -123,7 +79,7 @@ private:
|
|||
QMutex mutex;
|
||||
|
||||
QThread* workerThread;
|
||||
SelfCamWorker* worker;
|
||||
CameraWorker* worker;
|
||||
|
||||
QList<QSize> resolutions;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Volume Settings</string>
|
||||
<string>Volume Settings (Stubs)</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
|
|
Loading…
Reference in New Issue
Block a user