summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--video-ps3eye/CMakeLists.txt2
-rw-r--r--video-ps3eye/module.cpp156
-rw-r--r--video-ps3eye/module.hpp67
-rw-r--r--video-ps3eye/shm-layout.hpp4
-rw-r--r--video-ps3eye/wrapper.cxx31
5 files changed, 205 insertions, 55 deletions
diff --git a/video-ps3eye/CMakeLists.txt b/video-ps3eye/CMakeLists.txt
index 5f81b3fb..f357f965 100644
--- a/video-ps3eye/CMakeLists.txt
+++ b/video-ps3eye/CMakeLists.txt
@@ -49,7 +49,7 @@ endif()
if(TARGET ps3eye-subprocess)
otr_module(video-ps3eye)
- link_libraries(ps3eye-driver)
+ target_link_libraries(${self} ps3eye-driver opentrack-video)
if(WIN32)
set(path "${SDK_LIBUSB}/libusb-1.0.dll")
if(EXISTS "${path}")
diff --git a/video-ps3eye/module.cpp b/video-ps3eye/module.cpp
index ac6d8807..26b771e2 100644
--- a/video-ps3eye/module.cpp
+++ b/video-ps3eye/module.cpp
@@ -1,7 +1,19 @@
#include "module.hpp"
-#if 0
+#include "compat/library-path.hpp"
+#include "compat/sleep.hpp"
+#include "compat/run-in-thread.hpp"
+
+#include <cstddef>
+
+#include <QCoreApplication>
+#include <QMessageBox>
+
#include <libusb.h>
+#ifdef __GNUG__
+# pragma clang diagnostic ignored "-Wcast-qual"
+#endif
+
int device_count()
{
libusb_context * ctx = nullptr;
@@ -50,8 +62,6 @@ bool check_device_exists()
static const QString camera_name = QStringLiteral("PS3 Eye open driver");
-namespace video::impl {
-
std::vector<QString> ps3eye_camera_::camera_names() const
{
if (check_device_exists())
@@ -66,16 +76,150 @@ std::unique_ptr<camera> ps3eye_camera_::make_camera(const QString& name)
else
return {};
}
-bool ps3eye_camera_::show_dialog(const QString& camera_name)
+bool ps3eye_camera_::show_dialog(const QString&)
{
// TODO
return false;
}
-bool ps3eye_camera_::can_show_dialog(const QString& camera_name)
+bool ps3eye_camera_::can_show_dialog(const QString&)
{
return false;
}
-} // ns video::impl
+ps3eye_camera::ps3eye_camera()
+{
+ if (!shm.success())
+ return;
+
+ static const QString library_path(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH);
+ wrapper.setWorkingDirectory(library_path);
+#ifdef _WIN32
+ wrapper.setProgram("\"ps3eye-subprocess.exe\"");
+#else
+ wrapper.setProgram("ps3eye-subprocess");
#endif
+}
+
+ps3eye_camera::~ps3eye_camera()
+{
+ stop();
+}
+
+void ps3eye_camera::stop()
+{
+ open = false;
+
+ if (wrapper.state() != QProcess::NotRunning)
+ {
+ if (shm.success())
+ {
+ volatile auto& ptr = *(ps3eye::shm*)shm.ptr();
+ ptr.in.do_exit = true;
+ if (!wrapper.waitForFinished(500))
+ wrapper.kill();
+ wrapper.waitForFinished(-1);
+ }
+ else
+ {
+ wrapper.kill();
+ wrapper.waitForFinished(-1);
+ }
+ }
+}
+
+bool ps3eye_camera::start(info& args)
+{
+ if (!shm.success())
+ return false;
+
+ volatile auto& ptr = *(ps3eye::shm*)shm.ptr();
+
+ using mode = ps3eye::shm_in::mode;
+
+ open = false;
+ fr = {};
+ fr.channels = 3;
+ fr.channel_size = 1;
+
+ if (!args.width || args.width > 320)
+ {
+ ptr.in.resolution = mode::vga;
+ fr.width = 640; fr.height = 480;
+ }
+ else
+ {
+ ptr.in.resolution = mode::qvga;
+ fr.width = 320; fr.height = 240;
+ }
+
+ ptr.in.framerate = (uint8_t)std::clamp(args.fps, 30, 187);
+ ptr.in.gain = (uint8_t)s.gain;
+ ptr.in.exposure = (uint8_t)s.exposure;
+
+ wrapper.start();
+
+ constexpr int sleep_ms = 10, max_sleeps = 5000/sleep_ms;
+
+ for (int i = 0; i < max_sleeps; i++)
+ {
+ if (ptr.out.timecode > 0)
+ goto ok;
+ portable::sleep(sleep_ms);
+ }
+
+ run_in_thread_async(qApp, [&]() {
+ QString error;
+ if (ptr.out.error_string[0] == '\0')
+ error = "Unknown error";
+ else
+ error = QString::fromLatin1((const char*)ptr.out.error_string,
+ strnlen((const char*)ptr.out.error_string, sizeof(ptr.out.error_string)));
+
+ QMessageBox::critical(nullptr, "Can't open camera", "PS3 Eye driver error: " + error, QMessageBox::Close);
+ });
+
+ return false;
+
+ok:
+ open = true;
+ return true;
+}
+
+std::tuple<const frame&, bool> ps3eye_camera::get_frame()
+{
+ volatile auto& ptr = *(ps3eye::shm*)shm.ptr();
+ constexpr int sleep_ms = 10;
+ constexpr int max_sleeps = 2000/sleep_ms;
+
+ if (!open)
+ goto fail;
+
+ for (int i = 0; i < max_sleeps; i++)
+ {
+ unsigned new_timecode = ptr.out.timecode;
+ if (timecode != new_timecode)
+ {
+ timecode = new_timecode;
+ goto ok;
+ }
+ portable::sleep(sleep_ms);
+ }
+
+fail:
+ stop();
+ return { fr, false };
+
+ static_assert(offsetof(decltype(ptr.out), data_640x480) == offsetof(decltype(ptr.out), data_320x240));
+
+ok:
+ fr.data = (unsigned char*)ptr.out.data_640x480;
+ return { fr, true};
+}
+
+bool ps3eye_camera::show_dialog()
+{
+ return false;
+}
+
+OTR_REGISTER_CAMERA(ps3eye_camera_)
diff --git a/video-ps3eye/module.hpp b/video-ps3eye/module.hpp
index 357af14c..73cdf04c 100644
--- a/video-ps3eye/module.hpp
+++ b/video-ps3eye/module.hpp
@@ -1,54 +1,51 @@
#pragma once
#include "video/camera.hpp"
+#include "shm-layout.hpp"
+#include "compat/shm.h"
+#include "options/options.hpp"
+#include "compat/macros1.h"
-#if 0
+using namespace options;
-namespace video {
+#include <QProcess>
-struct OTR_VIDEO_EXPORT camera_
+using video::impl::camera;
+using video::impl::camera_;
+using video::frame;
+
+struct settings : opts
{
- camera_();
- virtual ~camera_();
+ settings() : opts{"video-ps3eye"} {}
- virtual std::vector<QString> camera_names() const = 0;
- virtual std::unique_ptr<camera> make_camera(const QString& name) = 0;
- virtual bool show_dialog(const QString& camera_name) = 0;
- virtual bool can_show_dialog(const QString& camera_name) = 0;
+ value<slider_value> exposure{b, "exposure", {63, 0, 63}};
+ value<slider_value> gain{b, "gain", {30, 0, 63}};
};
-struct OTR_VIDEO_EXPORT camera
+struct ps3eye_camera final : video::impl::camera
{
- struct info final
- {
- // TODO: expose FOV-based focal length for regular webcams
- int width = 0, height = 0, fps = 0;
- double fx = 0, fy = 0; // focal length
- double P_x = 0, P_y = 0; // principal point
- double dist_c[8] {}; // distortion coefficients
- };
-
- camera();
- virtual ~camera();
-
- [[nodiscard]] virtual bool start(info& args) = 0;
- virtual void stop() = 0;
- virtual bool is_open() = 0;
-
- virtual std::tuple<const frame&, bool> get_frame() = 0;
- [[nodiscard]] virtual bool show_dialog() = 0;
+ QProcess wrapper;
+ shm_wrapper shm { "ps3eye-driver-shm", nullptr, sizeof(ps3eye::shm) };
+ settings s;
+ frame fr;
+ bool open = false;
+ unsigned timecode = 0;
+
+ ps3eye_camera();
+ ~ps3eye_camera() override;
+
+ bool start(info& args) override;
+ void stop() override;
+ bool is_open() override { return open; }
+
+ std::tuple<const frame&, bool> get_frame() override;
+ [[nodiscard]] bool show_dialog() override;
};
-} // ns video
-
-#endif
-
-namespace video::impl {
-struct ps3eye_camera_ : camera_
+struct ps3eye_camera_ final : video::impl::camera_
{
std::vector<QString> camera_names() const override;
std::unique_ptr<camera> make_camera(const QString& name) override;
bool show_dialog(const QString& camera_name) override;
bool can_show_dialog(const QString& camera_name) override;
};
-} // ns video::impl
diff --git a/video-ps3eye/shm-layout.hpp b/video-ps3eye/shm-layout.hpp
index eba4b8b0..2335eab8 100644
--- a/video-ps3eye/shm-layout.hpp
+++ b/video-ps3eye/shm-layout.hpp
@@ -8,7 +8,7 @@ struct shm_in {
enum class status : uint8_t { starting, running, fail, terminate, };
uint32_t settings_updated;
- uint16_t framerate;
+ uint8_t framerate;
mode resolution;
status status_;
//uint8_t sharpness, contrast, brightness hue, saturation;
@@ -19,11 +19,11 @@ struct shm_in {
struct shm_out {
uint32_t timecode;
uint32_t settings_updated_ack;
+ char error_string[256];
union {
uint8_t data_320x240[320][240][3];
uint8_t data_640x480[640][480][3];
};
- char error_string[256];
};
struct shm {
diff --git a/video-ps3eye/wrapper.cxx b/video-ps3eye/wrapper.cxx
index be9e338e..0f063097 100644
--- a/video-ps3eye/wrapper.cxx
+++ b/video-ps3eye/wrapper.cxx
@@ -3,6 +3,8 @@
#include "ps3eye-driver/ps3eye.hpp"
+#include <thread>
+#include <chrono>
#include <cstdlib>
#ifdef __clang__
@@ -32,7 +34,8 @@ static void error(volatile ps3eye::shm_out& out, const char (&error)[N], const x
static void update_settings(ps3eye::camera& camera, const volatile ps3eye::shm_in& in)
{
- camera.set_framerate(in.framerate);
+ // TODO
+ //camera.set_framerate(in.framerate);
camera.set_auto_gain(in.auto_gain);
camera.set_gain(in.gain);
camera.set_exposure(in.exposure);
@@ -44,7 +47,7 @@ int main(int argc, char** argv)
(void)argc; (void)argv;
shm_wrapper mem_("ps3eye-driver-shm", nullptr, sizeof(ps3eye::shm));
volatile auto& ptr_ = *(ps3eye::shm*)mem_.ptr();
- const volatile auto& in = ptr_.in;
+ volatile auto& in = ptr_.in;
volatile auto& out = ptr_.out;
auto cameras = ps3eye::list_devices();
@@ -53,6 +56,7 @@ int main(int argc, char** argv)
error(out, "no camera found");
auto& camera = cameras[0];
+ camera->set_debug(false);
uint8_t* frame;
decltype(out.timecode) timecode = 0;
@@ -75,12 +79,18 @@ int main(int argc, char** argv)
if (!framerate)
framerate = 60;
- bool ret = camera->init(mode, framerate) && camera->start();
- if (!ret)
+ if (!camera->init(mode, framerate))
error(out, "camera init failed: %s", camera->error_string());
+
+ update_settings(*camera, in);
+
+ if (!camera->start())
+ error(out, "can't start camera: %s", camera->error_string());
}
- update_settings(*camera, in);
+ out.timecode = 0;
+ in.do_exit = false;
+ FULL_BARRIER();
for (;;)
{
@@ -93,12 +103,11 @@ int main(int argc, char** argv)
}
}
- bool success = true;
-
- success &= camera->get_frame(frame);
-
- if (!success)
- error(out, "error %s", camera->error_string());
+ if (!camera->get_frame(frame))
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds{4});
+ continue;
+ }
out.timecode = ++timecode;