|
From: Tapio V. <aa...@us...> - 2010-05-11 21:50:33
|
Module: performous
Branch: master
Commit: ca00c323c43e578cd5553f5ca0bc1545494a6907
Author: Tapio Vierros <tap...@gm...>
Date: Sun May 9 23:24:47 2010 +0300
Threaded webcam - much better framerate.
---
game/screen_sing.cc | 7 +++--
game/webcam.cc | 52 +++++++++++++++++++++++++++++++++++++++-----------
game/webcam.hh | 28 +++++++++++++++++++++++---
3 files changed, 68 insertions(+), 19 deletions(-)
diff --git a/game/screen_sing.cc b/game/screen_sing.cc
index fec2a0c..20d5549 100644
--- a/game/screen_sing.cc
+++ b/game/screen_sing.cc
@@ -248,7 +248,8 @@ void ScreenSing::manageEvent(SDL_Event event) {
if (key == SDLK_k) dispInFlash(++config["game/karaoke_mode"]); // Toggle karaoke mode
if (key == SDLK_w) dispInFlash(++config["game/pitch"]); // Toggle pitch wave
#ifdef USE_OPENCV
- if (key == SDLK_a) dispInFlash(++config["graphic/webcam"]); // Toggle webcam
+ // Toggle webcam
+ if (key == SDLK_a) { dispInFlash(++config["graphic/webcam"]); m_cam->pause(!config["graphic/webcam"].b()); }
#endif
// Latency settings
if (key == SDLK_F1) dispInFlash(--config["audio/video_delay"]);
@@ -306,9 +307,9 @@ void ScreenSing::draw() {
m_background->draw();
} else fillBG();
// Video
- if (m_video && !m_cam && !(*m_cam)()) { m_video->render(time); double tmp = m_video->dimensions().ar(); if (tmp > 0.0) ar = tmp; }
+ if (m_video && !m_cam && !m_cam->is_good()) { m_video->render(time); double tmp = m_video->dimensions().ar(); if (tmp > 0.0) ar = tmp; }
// Webcam
- if (m_cam && config["graphic/webcam"].b()) m_cam->render(time);
+ if (m_cam && config["graphic/webcam"].b()) m_cam->render();
// Top/bottom borders
ar = clamp(ar, arMin, arMax);
double offset = 0.5 / ar + 0.2;
diff --git a/game/webcam.cc b/game/webcam.cc
index aa35dd0..e9877df 100644
--- a/game/webcam.cc
+++ b/game/webcam.cc
@@ -1,35 +1,63 @@
#include <iostream>
#include "webcam.hh"
+#include "xtime.hh"
-Webcam::Webcam(int cam_id): m_capture(NULL), m_timestamp(0) {
+Webcam::Webcam(int cam_id):
+ m_capture(NULL), m_frameAvailable(false), m_running(false), m_quit(false)
+ {
#ifdef USE_OPENCV
m_capture = cvCaptureFromCAM(cam_id);
- if (!m_capture)
+ if (!m_capture) {
std::cout << "Could not initialize webcam capturing!" << std::endl;
+ return;
+ }
+ m_thread.reset(new boost::thread(boost::ref(*this)));
#else
++cam_id; // dummy
#endif
}
Webcam::~Webcam() {
+ m_quit = true;
#ifdef USE_OPENCV
+ m_thread->join();
cvReleaseCapture(&m_capture);
#endif
}
-void Webcam::render(double time) {
+void Webcam::operator()() {
#ifdef USE_OPENCV
- if (!m_capture) return;
- IplImage* frame = 0;
- if (time > m_timestamp + 0.5) {
- frame = cvQueryFrame(m_capture);
- if (!frame) return;
- m_surface.load(frame->width, frame->height, pix::RGB, (const unsigned char*)frame->imageData);
- m_timestamp = time;
+ m_running = true;
+ while (!m_quit) {
+ IplImage* frame = 0;
+ if (m_running) frame = cvQueryFrame(m_capture);
+ if (frame) {
+ boost::mutex::scoped_lock l(m_mutex);
+ m_frame.width = frame->width;
+ m_frame.height = frame->height;
+ m_frame.data.assign(frame->imageData, frame->imageData + (m_frame.width * m_frame.height * 3));
+ m_frameAvailable = true;
+ }
+ boost::thread::sleep(now() + (m_running ? 0.05 : 0.5));
+ }
+ #endif
+}
+
+void Webcam::pause(bool do_pause) {
+ boost::mutex::scoped_lock l(m_mutex);
+ m_running = !do_pause;
+ m_frameAvailable = false;
+}
+
+void Webcam::render() {
+ #ifdef USE_OPENCV
+ if (!m_capture || !m_running) return;
+ if (m_frameAvailable && !m_frame.data.empty()) {
+ boost::mutex::scoped_lock l(m_mutex);
+ m_surface.load(m_frame.width, m_frame.height, pix::RGB, &m_frame.data[0]);
+ m_frameAvailable = false;
}
m_surface.draw();
- #else
- ++time; // dummy
#endif
}
diff --git a/game/webcam.hh b/game/webcam.hh
index b64bece..a5c17b5 100644
--- a/game/webcam.hh
+++ b/game/webcam.hh
@@ -7,8 +7,18 @@
typedef void CvCapture;
#endif
+#include <boost/scoped_ptr.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+
#include "surface.hh"
+struct CamFrame {
+ int width;
+ int height;
+ std::vector<uint8_t> data;
+};
+
class Webcam {
public:
/// cam_id -1 means pick any device
@@ -16,16 +26,26 @@ class Webcam {
~Webcam();
- /// Is good?
- bool operator()() { return m_capture != 0; }
+ /// Thread runs here, don't call directly
+ void operator()();
- void render(double time);
+ /// Is good?
+ bool is_good() { return m_capture != 0; }
+ /// When paused, does not get or render frames
+ void pause(bool do_pause = true);
+ /// Display frame
+ void render();
Dimensions& dimensions() { return m_surface.dimensions; }
Dimensions const& dimensions() const { return m_surface.dimensions; }
private:
+ boost::scoped_ptr<boost::thread> m_thread;
+ mutable boost::mutex m_mutex;
CvCapture* m_capture;
+ CamFrame m_frame;
Surface m_surface;
- double m_timestamp;
+ bool m_frameAvailable;
+ volatile bool m_running;
+ volatile bool m_quit;
};
|