From de1445cdd8823d9c7d993e471a0aada92c38c039 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 8 Oct 2014 16:37:42 +0200 Subject: [PATCH] cleanup, split --- cameraworker.cpp | 205 ++++++++++++++++++++++++++++ cameraworker.h | 77 +++++++++++ qtox.pro | 6 +- widget/camera.cpp | 209 ++--------------------------- widget/camera.h | 50 +------ widget/form/settings/avsettings.ui | 2 +- 6 files changed, 299 insertions(+), 250 deletions(-) create mode 100644 cameraworker.cpp create mode 100644 cameraworker.h diff --git a/cameraworker.cpp b/cameraworker.cpp new file mode 100644 index 000000000..b0c964bc5 --- /dev/null +++ b/cameraworker.cpp @@ -0,0 +1,205 @@ +/* + Copyright (C) 2014 by Project Tox + + 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 +#include + +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 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; +} diff --git a/cameraworker.h b/cameraworker.h new file mode 100644 index 000000000..47fb10f87 --- /dev/null +++ b/cameraworker.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2014 by Project Tox + + 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 +#include +#include +#include +#include +#include + +#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 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 queue; + QTimer* clock; + cv::VideoCapture cam; + cv::Mat3b frame; + int camIndex; + QMap props; + QList resolutions; + int refCount; +}; + +#endif // CAMERAWORKER_H diff --git a/qtox.pro b/qtox.pro index 7849ed576..aadec52f6 100644 --- a/qtox.pro +++ b/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 diff --git a/widget/camera.cpp b/widget/camera.cpp index 7b2aa6a0c..6f66234a4 100644 --- a/widget/camera.cpp +++ b/widget/camera.cpp @@ -16,10 +16,9 @@ #include "camera.h" #include "widget.h" -#include +#include "cameraworker.h" #include #include -#include 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 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; -} diff --git a/widget/camera.h b/widget/camera.h index bf7380f7a..c26420953 100644 --- a/widget/camera.h +++ b/widget/camera.h @@ -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 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 qeue; - QTimer* clock; - cv::VideoCapture cam; - cv::Mat3b frame; - int camIndex; - QMap props; - QList resolutions; - int refCount; -}; - class Camera : public VideoSource { Q_OBJECT @@ -123,7 +79,7 @@ private: QMutex mutex; QThread* workerThread; - SelfCamWorker* worker; + CameraWorker* worker; QList resolutions; diff --git a/widget/form/settings/avsettings.ui b/widget/form/settings/avsettings.ui index 33a0edcbc..20ebbf43e 100644 --- a/widget/form/settings/avsettings.ui +++ b/widget/form/settings/avsettings.ui @@ -17,7 +17,7 @@ - Volume Settings + Volume Settings (Stubs)