diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 571febaffd..d4f42160d9 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -68,7 +68,7 @@ include(${QT_USE_FILE}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}") # run qt moc on qt-enabled headers -qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h) +qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h) # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS}) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fcc287c235..14c96e5186 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1569,9 +1569,6 @@ void Application::update(float deltaTime) { // Update transmitter - // Get the webcam frame - _webcam.grabFrame(); - // Sample hardware, update view frustum if needed, and send avatar data to mixer/agents updateAvatar(deltaTime); @@ -2154,26 +2151,28 @@ void Application::displayOverlay() { } // render the webcam input frame - glBindTexture(GL_TEXTURE_2D, _webcam.getFrameTextureID()); - glEnable(GL_TEXTURE_2D); - glColor3f(1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - const int FRAME_PREVIEW_HEIGHT = 200; - int framePreviewWidth = _webcam.getFrameAspectRatio() * FRAME_PREVIEW_HEIGHT; - int bottom = _glWidget->height() - 400; - int left = _glWidget->width() - framePreviewWidth - 400; - - glTexCoord2f(0, 0); - glVertex2f(left, bottom); - glTexCoord2f(1, 0); - glVertex2f(left + framePreviewWidth, bottom); - glTexCoord2f(1, 1); - glVertex2f(left + framePreviewWidth, bottom + FRAME_PREVIEW_HEIGHT); - glTexCoord2f(0, 1); - glVertex2f(left, bottom + FRAME_PREVIEW_HEIGHT); - glEnd(); - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); + if (_webcam.getFrameTextureID() != 0) { + glBindTexture(GL_TEXTURE_2D, _webcam.getFrameTextureID()); + glEnable(GL_TEXTURE_2D); + glColor3f(1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + const int FRAME_PREVIEW_HEIGHT = 200; + int framePreviewWidth = _webcam.getFrameAspectRatio() * FRAME_PREVIEW_HEIGHT; + int bottom = _glWidget->height() - 400; + int left = _glWidget->width() - framePreviewWidth - 400; + + glTexCoord2f(0, 0); + glVertex2f(left, bottom); + glTexCoord2f(1, 0); + glVertex2f(left + framePreviewWidth, bottom); + glTexCoord2f(1, 1); + glVertex2f(left + framePreviewWidth, bottom + FRAME_PREVIEW_HEIGHT); + glTexCoord2f(0, 1); + glVertex2f(left, bottom + FRAME_PREVIEW_HEIGHT); + glEnd(); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + } glPopMatrix(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index a0b1db78a6..7b1a7fac8b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -76,6 +76,7 @@ public: VoxelSystem* getVoxels() { return &_voxels; } QSettings* getSettings() { return _settings; } Environment* getEnvironment() { return &_environment; } + Webcam* getWebcam() { return &_webcam; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } diff --git a/interface/src/Webcam.cpp b/interface/src/Webcam.cpp index 5c08c500d3..554031704b 100644 --- a/interface/src/Webcam.cpp +++ b/interface/src/Webcam.cpp @@ -11,41 +11,83 @@ #include +#include "Application.h" #include "Webcam.h" -Webcam::Webcam() { - if ((_capture = cvCaptureFromCAM(-1)) == 0) { - printLog("Failed to open webcam.\n"); - return; - } +class FrameGrabber : public QObject { +public: - // get the dimensions, fps of the frames - _frameWidth = cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH); - _frameHeight = cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT); - int fps = cvGetCaptureProperty(_capture, CV_CAP_PROP_FPS); - printLog("Opened camera [width=%d, height=%d, fps=%d].", _frameWidth, _frameHeight, fps); -} + FrameGrabber() : _capture(0) { } + virtual ~FrameGrabber(); -void Webcam::init() { - // initialize the texture that will contain the grabbed frames - glGenTextures(1, &_frameTextureID); - glBindTexture(GL_TEXTURE_2D, _frameTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _frameWidth, _frameHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); -} +protected: + + virtual void timerEvent(QTimerEvent* event); + +private: + + CvCapture* _capture; +}; -Webcam::~Webcam() { +FrameGrabber::~FrameGrabber() { if (_capture != 0) { cvReleaseCapture(&_capture); } } -void Webcam::grabFrame() { +void FrameGrabber::timerEvent(QTimerEvent* event) { + if (_capture == 0) { + if ((_capture = cvCaptureFromCAM(-1)) == 0) { + printLog("Failed to open webcam.\n"); + return; + } + } IplImage* image = cvQueryFrame(_capture); if (image == 0) { return; } - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _frameWidth, _frameHeight, GL_RGB, GL_UNSIGNED_BYTE, image->imageData); + // make sure it's in the format we expect + if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U || image->dataOrder != IPL_DATA_ORDER_PIXEL || + image->origin != 0 || image->widthStep != image->width * 3) { + printLog("Invalid webcam image format.\n"); + return; + } + QMetaObject::invokeMethod(Application::getInstance()->getWebcam(), "setFrame", + Q_ARG(QImage, QImage((uchar*)image->imageData, image->width, image->height, QImage::Format_RGB888))); +} + +Webcam::Webcam() : _frameTextureID(0) { + // the grabber simply runs as fast as possible + _grabber = new FrameGrabber(); + _grabber->startTimer(0); + _grabber->moveToThread(&_grabberThread); +} + +void Webcam::init() { + // start the grabber thread + _grabberThread.start(); +} + +Webcam::~Webcam() { + // stop the grabber thread + _grabberThread.quit(); + _grabberThread.wait(); + + delete _grabber; +} + +void Webcam::setFrame(const QImage& image) { + if (_frameTextureID == 0) { + glGenTextures(1, &_frameTextureID); + glBindTexture(GL_TEXTURE_2D, _frameTextureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _frameWidth = image.width(), _frameHeight = image.height(), 0, GL_BGR, + GL_UNSIGNED_BYTE, image.constBits()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + } else { + glBindTexture(GL_TEXTURE_2D, _frameTextureID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _frameWidth, _frameHeight, GL_BGR, GL_UNSIGNED_BYTE, image.constBits()); + } glBindTexture(GL_TEXTURE_2D, 0); } + diff --git a/interface/src/Webcam.h b/interface/src/Webcam.h index f8692b0145..fb61bcec22 100644 --- a/interface/src/Webcam.h +++ b/interface/src/Webcam.h @@ -9,11 +9,20 @@ #ifndef __interface__Webcam__ #define __interface__Webcam__ +#include +#include + #include "InterfaceConfig.h" +class QImage; + struct CvCapture; -class Webcam { +class FrameGrabber; + +class Webcam : public QObject { + Q_OBJECT + public: Webcam(); @@ -26,11 +35,14 @@ public: float getFrameAspectRatio() const { return _frameWidth / (float)_frameHeight; } GLuint getFrameTextureID() const { return _frameTextureID; } - void grabFrame(); - +public slots: + + void setFrame(const QImage& image); + private: - CvCapture* _capture; + QThread _grabberThread; + FrameGrabber* _grabber; int _frameWidth; int _frameHeight;