/* 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; }