summaryrefslogtreecommitdiffstats
path: root/tradeshow/enterprise-kinectdatavis/src/quickfreenect/qquickfreenectbackend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tradeshow/enterprise-kinectdatavis/src/quickfreenect/qquickfreenectbackend.cpp')
-rw-r--r--tradeshow/enterprise-kinectdatavis/src/quickfreenect/qquickfreenectbackend.cpp232
1 files changed, 232 insertions, 0 deletions
diff --git a/tradeshow/enterprise-kinectdatavis/src/quickfreenect/qquickfreenectbackend.cpp b/tradeshow/enterprise-kinectdatavis/src/quickfreenect/qquickfreenectbackend.cpp
new file mode 100644
index 0000000..e32c20a
--- /dev/null
+++ b/tradeshow/enterprise-kinectdatavis/src/quickfreenect/qquickfreenectbackend.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: For any questions to Digia, please use the contact form at
+** http://www.qt.io
+**
+** This file is part of the examples of the Qt Enterprise Embedded.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qquickfreenectbackend.h"
+
+#include <QElapsedTimer>
+#include <QVector3D>
+#include "libfreenect.h"
+
+static std::weak_ptr<QQuickFreenectBackend> s_instance;
+
+std::shared_ptr<QQuickFreenectBackend> QQuickFreenectBackend::instance()
+{
+ std::shared_ptr<QQuickFreenectBackend> ret = s_instance.lock();
+ if (!ret)
+ s_instance = ret = std::shared_ptr<QQuickFreenectBackend>(new QQuickFreenectBackend);
+ return ret;
+}
+
+QQuickFreenectBackend::QQuickFreenectBackend()
+{
+ start();
+}
+
+QQuickFreenectBackend::~QQuickFreenectBackend()
+{
+ m_exitRequested = true;
+ wait();
+ s_instance.reset();
+}
+
+uint8_t *QQuickFreenectBackend::pickVideoFrontBuffer()
+{
+ QMutexLocker lock(&m_mutex);
+ if (m_gotVideoFrame) {
+ std::swap(m_videoMid, m_videoFront);
+ m_gotVideoFrame = false;
+ return m_videoFront;
+ }
+ return 0;
+}
+
+void QQuickFreenectBackend::run()
+{
+ freenect_context *f_ctx;
+ freenect_device *f_dev = 0;
+ QVector3D accelVectorAccum;
+ QVector3D emittedAccelVector;
+ QElapsedTimer accelVectorTimer;
+
+ accelVectorTimer.start();
+
+ if (freenect_init(&f_ctx, NULL) < 0) {
+ emit errorStringValue(QStringLiteral("Initialization of libfreenect failed, please restart."));
+ qWarning("freenect_init() failed");
+ return;
+ }
+
+#ifndef QT_NO_DEBUG
+ freenect_set_log_level(f_ctx, FREENECT_LOG_DEBUG);
+#endif
+ freenect_select_subdevices(f_ctx, (freenect_device_flags)(FREENECT_DEVICE_MOTOR | FREENECT_DEVICE_CAMERA));
+
+ int numDevices = freenect_num_devices(f_ctx);
+ if (!numDevices) {
+ emit errorStringValue(QStringLiteral("WARNING!\nNo Kinect detected, waiting for device..."));
+ qWarning("WARNING: No Kinect detected, make sure that udev permissions are set properly. See <src/libfreenect/platform/linux/udev/README>.");
+ }
+
+ int status = 0;
+ while (!m_exitRequested && status >= 0) {
+ // Set up the device
+ if (!f_dev) {
+ if (!(numDevices = freenect_num_devices(f_ctx))) {
+ timeval timeout{1, 0};
+ status = freenect_process_events_timeout(f_ctx, &timeout);
+ continue;
+ }
+
+ if (numDevices > 1)
+ qWarning("WARNING: More than one Kinect detected, using the first available.");
+ if (freenect_open_device(f_ctx, &f_dev, 0) < 0) {
+ emit errorStringValue(QStringLiteral("ERROR!\nCould open device. Please restart."));
+ freenect_shutdown(f_ctx);
+ return;
+ }
+
+ freenect_set_user(f_dev, this);
+ freenect_set_led(f_dev,LED_RED);
+ freenect_set_depth_callback(f_dev, depth_cb);
+ freenect_set_video_callback(f_dev, video_cb);
+ // Success.
+ emit errorStringValue(QString());
+ }
+
+ // Set up the depth stream
+ if (m_currentDepthStreamEnabled != m_requestedDepthStreamEnabled) {
+ if (m_requestedDepthStreamEnabled) {
+ freenect_set_depth_mode(f_dev, freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT));
+ m_depthBuffer = (uint16_t*)malloc(freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT).bytes);
+ freenect_set_depth_buffer(f_dev, m_depthBuffer);
+ freenect_start_depth(f_dev);
+ } else {
+ freenect_stop_depth(f_dev);
+ free(m_depthBuffer);
+ }
+ m_currentDepthStreamEnabled = m_requestedDepthStreamEnabled;
+ }
+
+ // Set up the video stream
+ if (m_currentVideoStream != m_requestedVideoStream) {
+ freenect_stop_video(f_dev);
+ // FIXME: Use YUV or BAYER instead.
+ freenect_video_format videoFormat = m_requestedVideoStream == QQuickFreenectVideoOutput::VideoRGB ? FREENECT_VIDEO_RGB : FREENECT_VIDEO_IR_8BIT;
+ free(m_videoBack);
+ free(m_videoMid);
+ free(m_videoFront);
+ m_videoBack = (uint8_t*)malloc(freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, videoFormat).bytes);
+ m_videoMid = (uint8_t*)malloc(freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, videoFormat).bytes);
+ m_videoFront = (uint8_t*)malloc(freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, videoFormat).bytes);
+ freenect_set_video_mode(f_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, videoFormat));
+ freenect_set_video_buffer(f_dev, m_videoBack);
+ freenect_start_video(f_dev);
+ m_currentVideoStream = m_requestedVideoStream;
+ }
+
+ if (m_requestedTiltDegrees != m_currentTiltDegrees) {
+ freenect_set_tilt_degs(f_dev, m_requestedTiltDegrees);
+ m_currentTiltDegrees = m_requestedTiltDegrees;
+ }
+
+ double dx, dy, dz;
+ freenect_update_tilt_state(f_dev);
+ freenect_get_mks_accel(freenect_get_tilt_state(f_dev), &dx, &dy, &dz);
+ // Weighted average of value updates over the last 100ms to flatten the noise.
+ float newVecRatio = std::min(100, (int)accelVectorTimer.elapsed()) / 100.;
+ accelVectorAccum = accelVectorAccum * (1. - newVecRatio) + QVector3D(dx, dy, dz) * newVecRatio;
+ accelVectorTimer.restart();
+ if (accelVectorAccum != emittedAccelVector) {
+ emit accelVectorValue(accelVectorAccum);
+ emittedAccelVector = accelVectorAccum;
+ }
+
+ // New accelerometer values seem to be available every ~5ms, make sure we come back to pick them.
+ timeval timeout{0, 5000};
+ status = freenect_process_events_timeout(f_ctx, &timeout);
+ }
+
+ if (status < 0) {
+ emit errorStringValue(QStringLiteral("ERROR!\nCould not read from device."));
+ freenect_shutdown(f_ctx);
+ return;
+ }
+
+ if (f_dev) {
+ freenect_stop_depth(f_dev);
+ freenect_stop_video(f_dev);
+ freenect_set_led(f_dev, LED_BLINK_GREEN);
+
+ freenect_close_device(f_dev);
+ }
+ freenect_shutdown(f_ctx);
+ free(m_videoBack);
+ free(m_videoMid);
+ free(m_videoFront);
+ free(m_depthBuffer);
+}
+
+void QQuickFreenectBackend::depth_cb(freenect_device *dev, void *buffer, uint32_t timestamp)
+{
+ Q_UNUSED(buffer)
+ Q_UNUSED(timestamp)
+ QQuickFreenectBackend *that = static_cast<QQuickFreenectBackend *>(freenect_get_user(dev));
+ ++that->m_depthFrameId;
+ emit that->depthFrameReady();
+}
+
+void QQuickFreenectBackend::video_cb(freenect_device *dev, void *buffer, uint32_t timestamp)
+{
+ Q_UNUSED(buffer)
+ Q_UNUSED(timestamp)
+ QQuickFreenectBackend *that = static_cast<QQuickFreenectBackend *>(freenect_get_user(dev));
+ {
+ QMutexLocker lock(&that->m_mutex);
+ Q_ASSERT(that->m_videoBack == buffer);
+ freenect_set_video_buffer(dev, that->m_videoMid);
+ std::swap(that->m_videoBack, that->m_videoMid);
+
+ // Don't notify if a stream change was requested
+ if (that->m_currentVideoStream == that->m_requestedVideoStream) {
+ that->m_gotVideoFrame = true;
+ emit that->videoFrameReady();
+ }
+ }
+}