1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

non-blocking cam communication, fixed CameraWorker::probeResolutions ...

called from wrong thread, try fix #408 and #495
This commit is contained in:
krepa098 2014-10-22 12:59:48 +02:00 committed by krepa098
parent 2d4329767e
commit c5dfb33999
7 changed files with 107 additions and 110 deletions

View File

@ -36,7 +36,10 @@ Camera::Camera()
connect(workerThread, &QThread::started, worker, &CameraWorker::onStart); connect(workerThread, &QThread::started, worker, &CameraWorker::onStart);
connect(workerThread, &QThread::finished, worker, &CameraWorker::deleteLater); connect(workerThread, &QThread::finished, worker, &CameraWorker::deleteLater);
connect(worker, &CameraWorker::newFrameAvailable, this, &Camera::onNewFrameAvailable); connect(worker, &CameraWorker::newFrameAvailable, this, &Camera::onNewFrameAvailable);
connect(worker, &CameraWorker::resProbingFinished, this, &Camera::onResProbingFinished);
connect(worker, &CameraWorker::resProbingFinished, this, &Camera::resolutionProbingFinished);
connect(worker, &CameraWorker::propProbingFinished, this, [=](int prop, double val) { emit propProbingFinished(Prop(prop), val); } );
workerThread->start(); workerThread->start();
} }
@ -48,29 +51,29 @@ Camera::~Camera()
void Camera::subscribe() void Camera::subscribe()
{ {
if (needsInit) if (refcount++ <= 0)
{
worker->probeResolutions();
needsInit = false;
}
if (refcount <= 0)
worker->resume(); worker->resume();
refcount++;
} }
void Camera::unsubscribe() void Camera::unsubscribe()
{ {
refcount--; if (--refcount <= 0)
if (refcount <= 0)
{ {
worker->suspend(); worker->suspend();
refcount = 0; refcount = 0;
} }
} }
void Camera::probeProp(Camera::Prop prop)
{
worker->probeProp(int(prop));
}
void Camera::probeResolutions()
{
worker->probeResolutions();
}
vpx_image Camera::getLastVPXImage() vpx_image Camera::getLastVPXImage()
{ {
QMutexLocker lock(&mutex); QMutexLocker lock(&mutex);
@ -115,75 +118,25 @@ vpx_image Camera::getLastVPXImage()
return img; return img;
} }
QList<QSize> Camera::getSupportedResolutions()
{
return resolutions;
}
QSize Camera::getBestVideoMode()
{
int bestScore = 0;
QSize bestRes;
for (QSize res : getSupportedResolutions())
{
int score = res.width() * res.height();
if (score > bestScore)
{
bestScore = score;
bestRes = res;
}
}
return bestRes;
}
void Camera::setResolution(QSize res) void Camera::setResolution(QSize res)
{ {
worker->setProp(CV_CAP_PROP_FRAME_WIDTH, res.width()); worker->setProp(CV_CAP_PROP_FRAME_WIDTH, res.width());
worker->setProp(CV_CAP_PROP_FRAME_HEIGHT, res.height()); worker->setProp(CV_CAP_PROP_FRAME_HEIGHT, res.height());
} }
QSize Camera::getResolution() QSize Camera::getCurrentResolution()
{ {
return QSize(worker->getProp(CV_CAP_PROP_FRAME_WIDTH), worker->getProp(CV_CAP_PROP_FRAME_HEIGHT)); return QSize(worker->getProp(CV_CAP_PROP_FRAME_WIDTH), worker->getProp(CV_CAP_PROP_FRAME_HEIGHT));
} }
void Camera::setProp(Camera::Prop prop, double val) void Camera::setProp(Camera::Prop prop, double val)
{ {
switch (prop) worker->setProp(int(prop), val);
{
case BRIGHTNESS:
worker->setProp(CV_CAP_PROP_BRIGHTNESS, val);
break;
case SATURATION:
worker->setProp(CV_CAP_PROP_SATURATION, val);
break;
case CONTRAST:
worker->setProp(CV_CAP_PROP_CONTRAST, val);
break;
case HUE:
worker->setProp(CV_CAP_PROP_HUE, val);
break;
}
} }
double Camera::getProp(Camera::Prop prop) double Camera::getProp(Camera::Prop prop)
{ {
switch (prop) return worker->getProp(int(prop));
{
case BRIGHTNESS:
return worker->getProp(CV_CAP_PROP_BRIGHTNESS);
case SATURATION:
return worker->getProp(CV_CAP_PROP_SATURATION);
case CONTRAST:
return worker->getProp(CV_CAP_PROP_CONTRAST);
case HUE:
return worker->getProp(CV_CAP_PROP_HUE);
}
return 0.0;
} }
void Camera::onNewFrameAvailable(const VideoFrame frame) void Camera::onNewFrameAvailable(const VideoFrame frame)
@ -195,11 +148,6 @@ void Camera::onNewFrameAvailable(const VideoFrame frame)
mutex.unlock(); mutex.unlock();
} }
void Camera::onResProbingFinished(QList<QSize> res)
{
resolutions = res;
}
Camera* Camera::getInstance() Camera* Camera::getInstance()
{ {
if (!instance) if (!instance)

View File

@ -36,11 +36,13 @@ class Camera : public VideoSource
{ {
Q_OBJECT Q_OBJECT
public: public:
enum Prop { enum Prop : int {
BRIGHTNESS, BRIGHTNESS = CV_CAP_PROP_BRIGHTNESS,
SATURATION, SATURATION = CV_CAP_PROP_SATURATION,
CONTRAST, CONTRAST = CV_CAP_PROP_CONTRAST,
HUE, HUE = CV_CAP_PROP_HUE,
WIDTH = CV_CAP_PROP_FRAME_WIDTH,
HEIGHT = CV_CAP_PROP_FRAME_HEIGHT,
}; };
~Camera(); ~Camera();
@ -48,19 +50,23 @@ public:
static Camera* getInstance(); ///< Returns the global widget's Camera instance static Camera* getInstance(); ///< Returns the global widget's Camera instance
vpx_image getLastVPXImage(); ///< Convert the last frame to a vpx_image (can be expensive !) vpx_image getLastVPXImage(); ///< Convert the last frame to a vpx_image (can be expensive !)
QList<QSize> getSupportedResolutions();
QSize getBestVideoMode();
void setResolution(QSize res); void setResolution(QSize res);
QSize getResolution(); QSize getCurrentResolution();
void setProp(Prop prop, double val); void setProp(Prop prop, double val);
double getProp(Prop prop); double getProp(Prop prop);
void probeProp(Prop prop);
void probeResolutions();
// VideoSource interface // VideoSource interface
virtual void subscribe(); virtual void subscribe();
virtual void unsubscribe(); virtual void unsubscribe();
signals:
void resolutionProbingFinished(QList<QSize> res);
void propProbingFinished(Prop prop, double val);
protected: protected:
Camera(); Camera();
@ -79,7 +85,6 @@ private:
private slots: private slots:
void onNewFrameAvailable(const VideoFrame frame); void onNewFrameAvailable(const VideoFrame frame);
void onResProbingFinished(QList<QSize> res);
}; };

View File

@ -18,7 +18,7 @@
#include <QTimer> #include <QTimer>
#include <QDebug> #include <QDebug>
#include <QCoreApplication> #include <QThread>
CameraWorker::CameraWorker(int index) CameraWorker::CameraWorker(int index)
: clock(nullptr) : clock(nullptr)
@ -26,6 +26,7 @@ CameraWorker::CameraWorker(int index)
, refCount(0) , refCount(0)
{ {
qRegisterMetaType<VideoFrame>(); qRegisterMetaType<VideoFrame>();
qRegisterMetaType<QList<QSize>>();
} }
void CameraWorker::onStart() void CameraWorker::onStart()
@ -67,13 +68,14 @@ double CameraWorker::_getProp(int prop)
{ {
subscribe(); subscribe();
props[prop] = cam.get(prop); props[prop] = cam.get(prop);
emit propProbingFinished(prop, props[prop]);
unsubscribe(); unsubscribe();
} }
return props.value(prop); return props.value(prop);
} }
void CameraWorker::probeResolutions() void CameraWorker::_probeResolutions()
{ {
if (resolutions.isEmpty()) if (resolutions.isEmpty())
{ {
@ -115,9 +117,9 @@ void CameraWorker::probeResolutions()
} }
unsubscribe(); unsubscribe();
}
qDebug() << "Camera resolutions:" << resolutions; qDebug() << "CameraWorker: Resolutions" <<resolutions;
}
emit resProbingFinished(resolutions); emit resProbingFinished(resolutions);
} }
@ -133,7 +135,7 @@ void CameraWorker::applyProps()
void CameraWorker::subscribe() void CameraWorker::subscribe()
{ {
if (refCount == 0) if (refCount++ == 0)
{ {
if (!cam.isOpened()) if (!cam.isOpened())
{ {
@ -142,15 +144,11 @@ void CameraWorker::subscribe()
applyProps(); // restore props applyProps(); // restore props
} }
} }
refCount++;
} }
void CameraWorker::unsubscribe() void CameraWorker::unsubscribe()
{ {
refCount--; if(--refCount <= 0)
if(refCount <= 0)
{ {
cam.release(); cam.release();
refCount = 0; refCount = 0;
@ -188,10 +186,19 @@ void CameraWorker::setProp(int prop, double val)
QMetaObject::invokeMethod(this, "_setProp", Q_ARG(int, prop), Q_ARG(double, val)); QMetaObject::invokeMethod(this, "_setProp", Q_ARG(int, prop), Q_ARG(double, val));
} }
void CameraWorker::probeProp(int prop)
{
QMetaObject::invokeMethod(this, "_getProp", Q_ARG(int, prop));
}
void CameraWorker::probeResolutions()
{
QMetaObject::invokeMethod(this, "_probeResolutions");
}
double CameraWorker::getProp(int prop) double CameraWorker::getProp(int prop)
{ {
double ret = 0.0; double ret = 0.0;
qApp->processEvents();
QMetaObject::invokeMethod(this, "_getProp", Qt::BlockingQueuedConnection, Q_RETURN_ARG(double, ret), Q_ARG(int, prop)); QMetaObject::invokeMethod(this, "_getProp", Qt::BlockingQueuedConnection, Q_RETURN_ARG(double, ret), Q_ARG(int, prop));
return ret; return ret;

View File

@ -40,21 +40,24 @@ public:
void resume(); void resume();
void setProp(int prop, double val); void setProp(int prop, double val);
double getProp(int prop); // blocking call! double getProp(int prop); // blocking call!
void probeResolutions();
public slots: public slots:
void onStart(); void onStart();
void probeProp(int prop);
void probeResolutions();
signals: signals:
void started(); void started();
void newFrameAvailable(const VideoFrame frame); void newFrameAvailable(const VideoFrame frame);
void resProbingFinished(QList<QSize> res); void resProbingFinished(QList<QSize> res);
void propProbingFinished(int prop, double val);
private slots: private slots:
void _suspend(); void _suspend();
void _resume(); void _resume();
void _setProp(int prop, double val); void _setProp(int prop, double val);
double _getProp(int prop); double _getProp(int prop);
void _probeResolutions();
private: private:
void applyProps(); void applyProps();

View File

@ -15,7 +15,6 @@
*/ */
#include "avform.h" #include "avform.h"
#include "src/camera.h"
#include "ui_avsettings.h" #include "ui_avsettings.h"
AVForm::AVForm() : AVForm::AVForm() :
@ -23,6 +22,9 @@ AVForm::AVForm() :
{ {
bodyUI = new Ui::AVSettings; bodyUI = new Ui::AVSettings;
bodyUI->setupUi(this); bodyUI->setupUi(this);
connect(Camera::getInstance(), &Camera::propProbingFinished, this, &AVForm::onPropProbingFinished);
connect(Camera::getInstance(), &Camera::resolutionProbingFinished, this, &AVForm::onResProbingFinished);
} }
AVForm::~AVForm() AVForm::~AVForm()
@ -34,15 +36,12 @@ void AVForm::present()
{ {
bodyUI->CamVideoSurface->setSource(Camera::getInstance()); bodyUI->CamVideoSurface->setSource(Camera::getInstance());
bodyUI->videoModescomboBox->clear(); Camera::getInstance()->probeProp(Camera::SATURATION);
QList<QSize> res = Camera::getInstance()->getSupportedResolutions(); Camera::getInstance()->probeProp(Camera::CONTRAST);
for (QSize r : res) Camera::getInstance()->probeProp(Camera::BRIGHTNESS);
bodyUI->videoModescomboBox->addItem(QString("%1x%2").arg(QString::number(r.width()),QString::number(r.height()))); Camera::getInstance()->probeProp(Camera::HUE);
bodyUI->ContrastSlider->setValue(Camera::getInstance()->getProp(Camera::CONTRAST)*100); Camera::getInstance()->probeResolutions();
bodyUI->BrightnessSlider->setValue(Camera::getInstance()->getProp(Camera::BRIGHTNESS)*100);
bodyUI->SaturationSlider->setValue(Camera::getInstance()->getProp(Camera::SATURATION)*100);
bodyUI->HueSlider->setValue(Camera::getInstance()->getProp(Camera::HUE)*100);
} }
void AVForm::on_ContrastSlider_sliderMoved(int position) void AVForm::on_ContrastSlider_sliderMoved(int position)
@ -65,13 +64,39 @@ void AVForm::on_HueSlider_sliderMoved(int position)
Camera::getInstance()->setProp(Camera::HUE, position / 100.0); Camera::getInstance()->setProp(Camera::HUE, position / 100.0);
} }
void AVForm::on_videoModescomboBox_currentIndexChanged(const QString &arg1) void AVForm::on_videoModescomboBox_activated(int index)
{ {
QStringList resStr = arg1.split("x"); Camera::getInstance()->setResolution(bodyUI->videoModescomboBox->itemData(index).toSize());
int w = resStr[0].toInt(); }
int h = resStr[0].toInt();
Camera::getInstance()->setResolution(QSize(w,h)); void AVForm::onPropProbingFinished(Camera::Prop prop, double val)
{
switch (prop)
{
case Camera::BRIGHTNESS:
bodyUI->BrightnessSlider->setValue(val*100);
break;
case Camera::CONTRAST:
bodyUI->ContrastSlider->setValue(val*100);
break;
case Camera::SATURATION:
bodyUI->SaturationSlider->setValue(val*100);
break;
case Camera::HUE:
bodyUI->HueSlider->setValue(val*100);
break;
default:
break;
}
}
void AVForm::onResProbingFinished(QList<QSize> res)
{
bodyUI->videoModescomboBox->clear();
for (QSize r : res)
bodyUI->videoModescomboBox->addItem(QString("%1x%2").arg(QString::number(r.width()),QString::number(r.height())), r);
bodyUI->videoModescomboBox->setCurrentIndex(bodyUI->videoModescomboBox->count()-1);
} }
void AVForm::hideEvent(QHideEvent *) void AVForm::hideEvent(QHideEvent *)

View File

@ -19,6 +19,7 @@
#include "genericsettings.h" #include "genericsettings.h"
#include "src/widget/videosurface.h" #include "src/widget/videosurface.h"
#include "src/camera.h"
#include <QGroupBox> #include <QGroupBox>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QPushButton> #include <QPushButton>
@ -43,7 +44,11 @@ private slots:
void on_SaturationSlider_sliderMoved(int position); void on_SaturationSlider_sliderMoved(int position);
void on_BrightnessSlider_sliderMoved(int position); void on_BrightnessSlider_sliderMoved(int position);
void on_HueSlider_sliderMoved(int position); void on_HueSlider_sliderMoved(int position);
void on_videoModescomboBox_currentIndexChanged(const QString &arg1); void on_videoModescomboBox_activated(int index);
// camera
void onPropProbingFinished(Camera::Prop prop, double val);
void onResProbingFinished(QList<QSize> res);
virtual void hideEvent(QHideEvent*); virtual void hideEvent(QHideEvent*);

View File

@ -130,10 +130,14 @@ void VideoSurface::paintGL()
VideoFrame currFrame = frame; VideoFrame currFrame = frame;
mutex.unlock(); mutex.unlock();
if (res != currFrame.resolution) if (res != currFrame.resolution && currFrame.resolution.isValid())
{ {
res = currFrame.resolution; res = currFrame.resolution;
// delete old texture
if (textureId != 0)
glDeleteTextures(1, &textureId);
// a texture used to render the pbo (has the match the pixelformat of the source) // a texture used to render the pbo (has the match the pixelformat of the source)
glGenTextures(1,&textureId); glGenTextures(1,&textureId);
glBindTexture(GL_TEXTURE_2D, textureId); glBindTexture(GL_TEXTURE_2D, textureId);
@ -148,7 +152,7 @@ void VideoSurface::paintGL()
if (pboAllocSize != currFrame.frameData.size()) if (pboAllocSize != currFrame.frameData.size())
{ {
qDebug() << "VideoSurface: Resize pbo " << currFrame.frameData.size() << "bytes (before" << pboAllocSize << ")"; qDebug() << "VideoSurface: Resize pbo " << currFrame.frameData.size() << "(" << currFrame.resolution << ")" << "bytes (before" << pboAllocSize << ")";
pbo[0]->bind(); pbo[0]->bind();
pbo[0]->allocate(currFrame.frameData.size()); pbo[0]->allocate(currFrame.frameData.size());